Многопоточное программирование на С++

Техносфера

Преподаватели

Дмитрий Калугин-Балашов

Руководитель группы разработки

d.kalugin-balashov@corp.mail.ru

Владислав Шпилевой

Программист

v.shpilevoy@corp.mail.ru

Максим Тремпольцев

Программист

m.trempoltsev@corp.mail.ru

Правила игры

  • 7 лекций
  • 7 практических заданий
  • 10 баллов каждое задание
  • дедлайн - 2 недели на задание
  • день опоздания - вычитается 2 балла
  • 5 - 70 баллов, 4 - 60 баллов, 3 - 50 баллов, остальное неуд.

Многопоточное программирование на С++

Лекция 1:

Контейнеры STL

Умные указатели

Аллокаторы

Техносфера

С++98

С++03 - патч для 98

С++11 - повышение абстракции

С++14 - auto auto auto

С++17 в разработке

Стандарты С++

С++98

С++03 - патч для 98

С++11 - повышение абстракции

С++14 - auto auto auto

С++17 в разработке

Стандарты С++

Контейнеры STL

  • Последовательные
  • Ассоциативные
  • Контейнеры-адаптеры
  • Псевдоконтейнеры
  • Хэш-таблицы

Это множества значений, или пар значений.

  • std::vector
  • std::deque
  • std::forward_list
  • std::list
  • std::array

Последовательные контейнеры STL

  • std::set
  • std::map
  • std::multiset
  • std::multimap
  • unordered модификации

Ассоциативные контейнеры STL

Двоичное дерево поиска

a1

a2

a4

a3

a5

a6

a8

a7

a9

a10

a  <  a

i

i + 1

Проблема двоичных деревьев

Несбалансированность

Красно-черные деревья

RB-дерево - двоичное дерево поиска с самобалансировкой

Правила:

  • Каждый узел имеет цвет
  • У красных вершин потомки черные
  • "Черный" путь от корня до любого листа неизменен

"Черная" высота = 2

RB-деревья: вставка и балансировка

Новый узел красный, но предок должен быть черным. Перекрасим вершины

A

B

C

D

A

B

C

D

Новое дерево удовлетворяет определению RB-дерева

...

...

...

...

...

...

RB-деревья: вставка и балансировка

A

B

C

D

Что, если перекрашивание не помогает?

Просто сделать B черным нельзя - может нарушиться "черная" высота дерева! Нужно выполнить поворот  перекраску дерева.

x

z

y

B

D

A

C

x

z

y

Новое дерево удовлетворяет определению RB-дерева

RB-деревья: удаление и балансировка

Del

null

null

Удалить и ребалансировать

Del

null

Заменить единственным потомком, ребалансировать

Chld

null

leaf

null

Del

leaf

Chld

subtree

Заменить наименьшим элементом из правого поддерева, ребалансировать

Chld

subtree

Удаление как в бинарном дереве + балансировка

Chld

RB-деревья: пример балансировки

http://goo.gl/vBHT7B

Ассоциативные контейнеры google

  • Реализованы через B-деревья
  • Источник: http://goo.gl/Dd4X1I

btree_set

btree_map

btree_multiset

btree_multimap

k1

k1

k1

k1

k1

k1

k1

k1

k1

k1

k1

k1

k1

k1

k1

k1

k1

k1

Контейнеры-адаптеры

  • std::queue
  • std::stack
  • std::priority_queue

Адаптер - обертка над другим контейнером, предоставляет стандартный интерфейс

Бэкэнд: std::list или std::deque

Бэкэнд: std::list, std::deque или std::vector

Бэкэнд: std::vector или std::deque

Псевдоконтейнеры

  • std::bitset
  • std::basic_string
  • std::valarray

Оптимизировано хранение, фиксирован размер, специальные ссылки

Для хранения строко-подобных объектов. Оптимизировано хранение, требует интерфейс.

Оптимальное хранение чисел и выполнение мат. операций. Расширенный интерфейс.

Хэш-таблицы

Хэш-функция - сюрьективное отображение

vlad

dima

leha

serg

max

ivan

1

4

2

3

  • Возможны коллизии: элементы разные, а хэш у них один (так как сюрьекция)
  • Стратегии разрешения коллизий - "ведра" или больше одной хэш-функции

Хэш-таблицы: коллизии

leha

serg

1

Коллизия. Решение - хранить список.

leha

serg

1

leha

serg

Второе решение - применять другие хэш функции к новому элементу, пока не получим не занятое значение хэша.

Хэш-таблицы STL

  • std::unordered_set
  • std::unordered_multiset
  • std::unordered_map
  • std::unordered_multimap

Boost circular buffer

boost::circular_buffer

boost::circular_buffer_space_optimized

Источник: http://goo.gl/myJ46d

Источник: http://goo.gl/PVu96v

Умные указатели

  • Поведение идентично простому указателю
  • Следит за освобождением памяти
#include <iostream>

class SmartIntPtr {
	int *ptr;
public:
	SmartIntPtr(int *src = nullptr) : ptr(src) { }

	~SmartIntPtr() {
		if (ptr != nullptr)
			delete ptr;
		std::cout << "deletion of data" << std::endl;
	}

	int &operator*() { return *ptr; }
};
int main()
{
	int *data = new int;
	*data = 10;
	SmartIntPtr smp(data);
	std::cout << "data: " << *smp
            << std::endl;
	return 0;
}
data: 10
deletion of data

Умные указатели: шаблоны

Можно унифицировать шаблонами

#include <iostream>

template<class T>
class SmartPtr {
	T *ptr;
public:
	SmartPtr(T *src = nullptr) : ptr(src) { }

	~SmartPtr() {
		if (ptr != nullptr)
			delete ptr;
		std::cout << "deletion of data" << std::endl;
	}

	T &operator*() { return *ptr; }

	T *operator->() { return ptr; }
};

struct MyStruct {
	int foo_bar;
	void call_me_please() {
            std::cout << "thanks"
                << std::endl;
        }
};

int main()
{
	SmartPtr<MyStruct> smp(new MyStruct);
	smp->call_me_please();
	return 0;
}
thanks
deletion of data

Умные указатели: существующие реализации

  • std::auto_ptr (deprecated)

Некорректное копирование указателя.

#include <memory>

int main()
{
	std::auto_ptr<int> p1(new int);
	std::auto_ptr<int> p2;
	p2 = p1;

	*p1 = 100; //Segmentation Fault
	
	return 0;
}

Умные указатели: существующие реализации

  • std::unique_ptr

Уникальное владение объектом

#include <memory>

int main()
{
	std::unique_ptr<int> p1(new int);
	std::unique_ptr<int> p2;
	
	p2 = p1; //Compilation Error
	
	return 0;
}

Перемещение специфицируется явно

#include <memory>

int main()
{
	std::unique_ptr<int> p1(new int);
	std::unique_ptr<int> p2;
	
	p2 = std::move(p1); //Ok
	
	return 0;
}

Умные указатели: существующие реализации

  • std::shared_ptr

Множественное владение объектом

#include <memory>

int main()
{
	std::shared_ptr<int> p1(new int);
	std::shared_ptr<int> p2;
        *p1 = 0;
	
	p2 = p1; //Ok
        *p2 = 20;
        std::cout << *p1 << std::endl;
        // Prints 20	

	return 0;
}

Отслеживает количество ссылок

Объект

cnt=3

ptr1

ptr2

ptr3

Умные указатели: существующие реализации

  • std::shared_ptr и проблема циклических ссылок
#include <memory>
#include <iostream>

struct A;
struct B {
	std::shared_ptr<A> p;
	~B() { std::cout << "destr B" << std::endl; }
};

struct A {
	std::shared_ptr<B> p;
	~A() { std::cout << "destr A" << std::endl; }
};

int main() {
	A *a = new A;
	B *b = new B;
	a->p.reset(b);
	b->p.reset(a);
	delete a;
	return 0;
}
$ ./a.out 
destr A
destr B
destr A
malloc: *** error pointer being
freed was not allocated
*** set a breakpoint in
malloc_error_break to debug
Abort trap: 6

Умные указатели: существующие реализации

  • std::shared_ptr и проблема циклических ссылок
  • Решение: std::weak_ptr
#include <memory>
#include <iostream>

struct A;
struct B {
	std::shared_ptr<A> p;
	~B() { std::cout << "destr B" << std::endl; }
};

struct A {
	std::weak_ptr<B> p;
	~A() { std::cout << "destr A" << std::endl; }
};

int main() {
	A *a = new A;
	B *b = new B;
	a->p = std::shared_ptr<B>(b);
	b->p.reset(a);
	delete a;
	return 0;
}
$ ./a.out 
destr B
destr A

Многопоточное программирование на С++

By Vladislav Shpilevoy

Многопоточное программирование на С++

  • 1,584