Автор: Толик
Головной раздел: Меню
Вопрос 27. Многозадачность в стандартной библиотеке C++: высокоуровневый интерфейс (функция std::async() и шаблон класса std::future< >), пример создания потока и получение результата потоковой функции.
std::async
позволяет выполнять функцию реально или мнимо параллельно.
std::future
предоставляет механизм взаимодействия с результатом асинхронной функции.
#include <future>
int counter()
{
int result = 0;
for (int i = 0; i < 10000; i++) {
result++; // Что-то делаем
}
return result;
}
int main()
{
std::future<int> handle = std::async(counter);
std::cout << handle.get() << std::endl;
}
Вопрос 28. Многозадачность в стандартной библиотеке C++: низкоуровневый интерфейс (использование класса std::thread), пример.
std::thread
создает отдельный поток, который будет выполняться мнимо или физически параллельно. В отличии от высокоуровневого интерфейса нельзя получить значение, которое вернет функция стандартным способом.
#include <thread>
void counter(int *num)
{
// Что-то делаем
for (int i = 0; i < 10000; i++) {
num++;
}
}
int main()
{
int number = 0;
std::thread thread(counter, &number);
// Что-то делаем
thread.join(); // Фиксируем прибыль (ждем, пока поток закончит)
std::cout << number << std::endl;
}
Вопрос 29. Синхронизация в стандартной библиотеке C++. Использование класса std::mutex (взаимное исключение), пример.
Основной способ синхронизации потоков - std::mutex
#include <mutex>
// Общие данные
std::mutex mutex;
// Thread 1
for (int i = 0; i < 100; i++) {
mutex.lock(); // Блокирует. Если уже заблокировано, то поток стоит и ждем
// Гарантируем, что вывод не "перемешается"
std::cout << "Part" << " " << "of" << " " << "text" << "." << "." << std::endl;
mutex.unlock();
}
// Thread 2
for (int i = 0; i < 100; i++) {
mutex.lock(); // Блокирует. Если уже заблокировано, то поток стоит и ждем
// Гарантируем, что вывод не "перемешается"
std::cout << "Part" << " " << "of" << " "
<< "the" << " "<< "second" << "." << "." << std::endl;
mutex.unlock();
}
Использование std::lock_guard
позволяет заблокировать std::mutex
в стиле RAII
#include <mutex>
// Где-то выше
std::mutex mutex;
// Где-то в коде
{
std::lock_guard<std::mutex> lock(mutex)
// Делаем что-то небезопасное
} // При попадении в исключение или при выходе из блока само unlock'нется
Вопрос 31.Использование условных переменных (объекты класса std::condition_variable) для синхронизации потоков в стандартной библиотеке C++: посылка и принятие оповещений потоками, примеры.
Назначение std::condition_variable
списываем из вопроса :)
#include <condition_variable>
// ...
// Общие переменные
std::mutex mutex;
std::condition_variable cv;
bool isDone = false;
// Thread 1
std::unique_lock<std::mutex> lock(mutex);
while (!isDone) { // Исключаем ложные срабатывания
cv.wait(lock); // Сработает, когда thread 2 пошлет
}
// Done!
// Thread 2
std::unique_lock<std::mutex> lock(mutex);
sleep(5); // Что-то делаем
isDone = true;
cv.notify_one();
Вопрос 32. Использование атомарных операций (шаблон std::atomic) для синхронизации потоков в стандартной библиотеке C++
Поведение объектов шаблонов std::atomic, при использовании в нескольких потоках, определено стандартом. То есть, рекомендуется их использовать при взаимодействии с несколькими потоками
#include <iostream>
#include <thread>
#include <atomic>
std::atomic<long long> data;
void do_work()
{
data += 1;
}
int main()
{
std::thread th1(do_work);
std::thread th2(do_work);
std::thread th3(do_work);
std::thread th4(do_work);
std::thread th5(do_work);
th1.join();
th2.join();
th3.join();
th4.join();
th5.join();
std::cout << "Result:" << data << '\n';
}