Skip to content

Instantly share code, notes, and snippets.

@NickTikhomirov
Last active June 19, 2019 17:58
Show Gist options
  • Save NickTikhomirov/bc07ae2f03c95003182708f6079e7b6e to your computer and use it in GitHub Desktop.
Save NickTikhomirov/bc07ae2f03c95003182708f6079e7b6e to your computer and use it in GitHub Desktop.
Потоки

Вопросы 27-31, Потоки

Автор: Толик

Головной раздел: Меню

Вопрос 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();
}

__________________________________________________________________

Вопрос 30. Использование для синхронизации потоков блокировок – шаблона std::lock_guard, пример.

Использование 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';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment