API для многопоточности появился в С++ начиная со стандарта C++11.
Создание и запуск потока
Запуск потока выполняется при его создании.
#include <iostream>
#include <thread>
void foo()
{
for (int i = 0; i < 10; i++)
{
std::cout << "foo" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void bar()
{
using namespace std::chrono_literals;
for (int i = 0; i < 10; i++)
{
std::cout << "bar" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main(int argc, char** argv)
{
// Functions, lambda expressions, function objects and even class member functions
// can be passed as parameters to theread constructor.
// Variable number of parameters can be passed to theread constructor
// because the counstructor is a variadic template.
std::thread thread1(foo);
std::thread thread2(bar);
thread1.join();
thread2.join();
return 0;
}
#include <thread>
void foo()
{
for (int i = 0; i < 10; i++)
{
std::cout << "foo" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void bar()
{
using namespace std::chrono_literals;
for (int i = 0; i < 10; i++)
{
std::cout << "bar" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main(int argc, char** argv)
{
// Functions, lambda expressions, function objects and even class member functions
// can be passed as parameters to theread constructor.
// Variable number of parameters can be passed to theread constructor
// because the counstructor is a variadic template.
std::thread thread1(foo);
std::thread thread2(bar);
thread1.join();
thread2.join();
return 0;
}
Интересные штуки:
- std::thread
- std::thread::join
- std::this_thread
- std::this_thread::sleep_for
Получение результата работы потока или исключения, произошедшего в нём
#include <iostream>
#include <thread>
#include <stdexcept>
int foo(int n)
{
if (n > 5)
throw std::exception("Error!!!");
int sum = 0;
for (int i = 1; i <= n; i++)
sum += i;
return sum;
}
void thread_function(
int param,
int& result,
std::exception_ptr& error)
{
try
{
result = foo(param);
}
catch (...)
{
error = std::current_exception();
}
}
int main(int argc, char** argv)
{
int param = 0;
int result = 0;
std::exception_ptr error;
std::cin >> param;
std::thread thr(
thread_function,
param, std::ref(result),
std::ref(error));
thr.join();
if (error)
{
try
{
std::rethrow_exception(error);
}
catch (const std::exception ex)
{
std::cout << ex.what() << std::endl;
}
}
else
std::cout << result;
return 0;
}
#include <thread>
#include <stdexcept>
int foo(int n)
{
if (n > 5)
throw std::exception("Error!!!");
int sum = 0;
for (int i = 1; i <= n; i++)
sum += i;
return sum;
}
void thread_function(
int param,
int& result,
std::exception_ptr& error)
{
try
{
result = foo(param);
}
catch (...)
{
error = std::current_exception();
}
}
int main(int argc, char** argv)
{
int param = 0;
int result = 0;
std::exception_ptr error;
std::cin >> param;
std::thread thr(
thread_function,
param, std::ref(result),
std::ref(error));
thr.join();
if (error)
{
try
{
std::rethrow_exception(error);
}
catch (const std::exception ex)
{
std::cout << ex.what() << std::endl;
}
}
else
std::cout << result;
return 0;
}
Интересные штуки:
- std::exception_ptr
- std::rethrow_exception
- std::ref
Атомарные операции
#include <atomic>
void thread_safe_increment(
std::atomic<int>& value)
{
value += 10;
}
void non_thread_safe_increment(
int& value)
{
value += 10;
}
void thread_safe_increment(
std::atomic<int>& value)
{
value += 10;
}
void non_thread_safe_increment(
int& value)
{
value += 10;
}
Интересные штуки:
- std::atomic<T>
Mutex
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mutual_exclusion;
void foo()
{
mutual_exclusion.lock();
try
{
for (int i = 0; i < 10; i++)
{
std::cout << "foo" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
mutual_exclusion.unlock();
}
catch (...)
{
mutual_exclusion.unlock();
}
}
void bar()
{
mutual_exclusion.lock();
try
{
for (int i = 0; i < 10; i++)
{
std::cout << "bar" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
mutual_exclusion.unlock();
}
catch (...)
{
mutual_exclusion.unlock();
}
}
int main(int argc, char** argv)
{
std::thread thread1(foo);
std::thread thread2(bar);
thread1.join();
thread2.join();
return 0;
}
#include <thread>
#include <mutex>
std::mutex mutual_exclusion;
void foo()
{
mutual_exclusion.lock();
try
{
for (int i = 0; i < 10; i++)
{
std::cout << "foo" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
mutual_exclusion.unlock();
}
catch (...)
{
mutual_exclusion.unlock();
}
}
void bar()
{
mutual_exclusion.lock();
try
{
for (int i = 0; i < 10; i++)
{
std::cout << "bar" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
mutual_exclusion.unlock();
}
catch (...)
{
mutual_exclusion.unlock();
}
}
int main(int argc, char** argv)
{
std::thread thread1(foo);
std::thread thread2(bar);
thread1.join();
thread2.join();
return 0;
}
Интересные штуки:
- std::mutex
- std::recursive_mutex
- std::mutex::lock
- std::mutex::try_lock
- std::mutex::unlock
- std::timed_mutex
- std::recursive_timed_mutex
- std::shared_timed_mutex
lock_guard (RAII style)
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mutual_exclusion;
void foo()
{
std::lock_guard<std::mutex> lock(mutual_exclusion);
for (int i = 0; i < 10; i++)
{
std::cout << "foo" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
void bar()
{
std::lock_guard<std::mutex> lock(mutual_exclusion);
for (int i = 0; i < 10; i++)
{
std::cout << "bar" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
int main(int argc, char** argv)
{
std::thread thread1(foo);
std::thread thread2(bar);
thread1.join();
thread2.join();
return 0;
}
#include <thread>
#include <mutex>
std::mutex mutual_exclusion;
void foo()
{
std::lock_guard<std::mutex> lock(mutual_exclusion);
for (int i = 0; i < 10; i++)
{
std::cout << "foo" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
void bar()
{
std::lock_guard<std::mutex> lock(mutual_exclusion);
for (int i = 0; i < 10; i++)
{
std::cout << "bar" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
int main(int argc, char** argv)
{
std::thread thread1(foo);
std::thread thread2(bar);
thread1.join();
thread2.join();
return 0;
}
Интересные штуки:
- std::lock_guard<T>
- std::unique_lock<T>
- std::shared_lock<T>
Захват нескольких lock’ов
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mutual_exclusion1;
std::mutex mutual_exclusion2;
void foo()
{
std::unique_lock<std::mutex> lock1(mutual_exclusion1, std::defer_lock_t());
std::unique_lock<std::mutex> lock2(mutual_exclusion2, std::defer_lock_t());
std::lock(lock1, lock2);
for (int i = 0; i < 10; i++)
{
std::cout << "foo" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
void bar()
{
std::unique_lock<std::mutex> lock1(mutual_exclusion1, std::defer_lock_t());
std::unique_lock<std::mutex> lock2(mutual_exclusion2, std::defer_lock_t());
std::lock(lock1, lock2);
for (int i = 0; i < 10; i++)
{
std::cout << "bar" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
int main(int argc, char** argv)
{
std::thread thread1(foo);
std::thread thread2(bar);
thread1.join();
thread2.join();
return 0;
}
#include <thread>
#include <mutex>
std::mutex mutual_exclusion1;
std::mutex mutual_exclusion2;
void foo()
{
std::unique_lock<std::mutex> lock1(mutual_exclusion1, std::defer_lock_t());
std::unique_lock<std::mutex> lock2(mutual_exclusion2, std::defer_lock_t());
std::lock(lock1, lock2);
for (int i = 0; i < 10; i++)
{
std::cout << "foo" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
void bar()
{
std::unique_lock<std::mutex> lock1(mutual_exclusion1, std::defer_lock_t());
std::unique_lock<std::mutex> lock2(mutual_exclusion2, std::defer_lock_t());
std::lock(lock1, lock2);
for (int i = 0; i < 10; i++)
{
std::cout << "bar" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
int main(int argc, char** argv)
{
std::thread thread1(foo);
std::thread thread2(bar);
thread1.join();
thread2.join();
return 0;
}
Интересные штуки:
- std::uniqie_lock<T>
- std::lock
Conditional Variables
Conditional Variable — это средство синхронизации потоков, которое аналогично Autoreset Event, с которым я знаком по опыту программирования в .NET. Служат conditional variables для того, чтобы подать сигнал потоку, ожидающему событие, о произошедшем событии.
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mutual_exclusion;
std::condition_variable cond_var;
void working_function()
{
std::unique_lock<std::mutex> lock(mutual_exclusion);
while (true)
{
cond_var.wait(lock);
std::cout << "working" << std::endl;
}
}
int main(int argc, char** argv)
{
std::thread thr(working_function);
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::unique_lock<std::mutex> lock(mutual_exclusion);
std::cout << "Do some work? (y/n): ";
char yes_no = 'n';
std::cin >> yes_no;
if (yes_no == 'y')
cond_var.notify_one();
}
return 0;
}
#include <thread>
#include <mutex>
std::mutex mutual_exclusion;
std::condition_variable cond_var;
void working_function()
{
std::unique_lock<std::mutex> lock(mutual_exclusion);
while (true)
{
cond_var.wait(lock);
std::cout << "working" << std::endl;
}
}
int main(int argc, char** argv)
{
std::thread thr(working_function);
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::unique_lock<std::mutex> lock(mutual_exclusion);
std::cout << "Do some work? (y/n): ";
char yes_no = 'n';
std::cin >> yes_no;
if (yes_no == 'y')
cond_var.notify_one();
}
return 0;
}
Интересные штуки:
- std::condition_variable
- std::condition_variable::wait
- std::condition_variable::notify_one
- std::condition_variable::notify_all
async, packaged_task, future, promise
#include <iostream>
#include <future>
int working_function(int n)
{
int sum = 0;
for (int i = 0; i < n; i++)
{
sum += i;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "working" << std::endl;
}
return sum;
}
int main(int argc, char** argv)
{
std::packaged_task<int(int)> task(working_function);
auto fut = task.get_future();
task(50);
std::cout << fut.get();
return 0;
}
#include <future>
int working_function(int n)
{
int sum = 0;
for (int i = 0; i < n; i++)
{
sum += i;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "working" << std::endl;
}
return sum;
}
int main(int argc, char** argv)
{
std::packaged_task<int(int)> task(working_function);
auto fut = task.get_future();
task(50);
std::cout << fut.get();
return 0;
}
Интересные штуки:
- std::packaged_task
- std::packaged_task::get_future
- std::future::get
#include <iostream>
#include <future>
int working_function(int n)
{
int sum = 0;
for (int i = 0; i < n; i++)
{
sum += i;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "working" << std::endl;
}
return sum;
}
int main(int argc, char** argv)
{
auto fut = std::async(std::launch::async, working_function, 50);
std::cout << fut.get();
return 0;
}
#include <future>
int working_function(int n)
{
int sum = 0;
for (int i = 0; i < n; i++)
{
sum += i;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "working" << std::endl;
}
return sum;
}
int main(int argc, char** argv)
{
auto fut = std::async(std::launch::async, working_function, 50);
std::cout << fut.get();
return 0;
}
Интересные штуки:
- std::async
#include <iostream>
#include <future>
#include <stdexcept>
int working_function(int n)
{
if (n > 100)
throw std::exception("Error!!!");
int sum = 0;
for (int i = 0; i < n; i++)
{
sum += i;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "working" << std::endl;
}
return sum;
}
int main(int argc, char** argv)
{
auto fut = std::async(std::launch::async, working_function, 200);
try
{
std::cout << fut.get();
}
catch (const std::exception& ex)
{
std::cout << ex.what();
}
return 0;
}
#include <future>
#include <stdexcept>
int working_function(int n)
{
if (n > 100)
throw std::exception("Error!!!");
int sum = 0;
for (int i = 0; i < n; i++)
{
sum += i;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "working" << std::endl;
}
return sum;
}
int main(int argc, char** argv)
{
auto fut = std::async(std::launch::async, working_function, 200);
try
{
std::cout << fut.get();
}
catch (const std::exception& ex)
{
std::cout << ex.what();
}
return 0;
}