多线程
C++11提供了thread
和mutex
等一系列的头文件, 但在windows下的mingw需要选择安装posix
多线程版本的才能使用, 下载地址: sourceforge, 拉到最下面选择第一个
Linux下就没这么多问题
thread
- 构造函数:
template< class Function, class... Args > explicit thread( Function&& f, Args&&... args );
: 第一个参数是一个函数, 后面的是该函数需要的参数 - 移动构造函数:
thread( thread&& other ) noexcept;
- 复制构造函数:
thread(const thread&) = delete;
: 删除, 不能使用, 也就是说不能复制一个线程 get_id
: 获取线程idjoin
: 等待线程结束detach
: 允许线程独立运行
参考: https://en.cppreference.com/w/cpp/thread/thread/thread
#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
void f1(int n)
{
for (int i = 0; i < 5; ++i) {
std::cout << "Thread 1 executing\n";
++n;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void f2(int& n)
{
for (int i = 0; i < 5; ++i) {
std::cout << "Thread 2 executing\n";
++n;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
class foo
{
public:
void bar()
{
for (int i = 0; i < 5; ++i) {
std::cout << "Thread 3 executing\n";
++n;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
int n = 0;
};
int main()
{
int n = 0;
foo f;
std::thread t1; // t1 is not a thread
std::thread t2(f1, n + 1); // pass by value
std::thread t3(f2, std::ref(n)); // pass by reference
std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
std::thread t5(&foo::bar, &f); // t5 runs foo::bar() on object f
t2.join();
t4.join();
t5.join();
std::cout << "Final value of n is " << n << '\n';
std::cout << "Final value of foo::n is " << f.n << '\n';
}
this_thread名称空间
std::this_thread::
是一个名称空间, 包含了一些有用的函数
-
get_id
: 获取当前线程的idstd::cout << std::this_thread::get_id() << std::endl;
-
sleep_for
: 当前线程休眠一段时间, 时间长度要用chrono
中的函数, 这些函数返回一个duration
对象代表指定的时间长度std::this_thread::sleep_for(std::chrono::seconds(2));
-
sleep_until
: 睡眠直到指定时间, 这个指定时间也要用chrone
中的函数得到一个time_point
对象 -
yield
: 让出CPU时间片
mutex
互斥量类, 有这么几种:
-
mutex
: 最基本的互斥量lock
: 请求, 如果没有成功则线程阻塞直到成功unlock
: 释放try_lock
:请求, 如果成功返回true
, 否则直接返回false
而不会阻塞
-
recursive_mutex
: 可递归, 和其他语言里面的一样 -
time_mutex
: 可定时, 多了下面这两个函数-
try_lock_for
: 和try_lock
一样, 不过会等待一段时间, 如果时间过了还是失败, 返回false
-
try_lock_until
: 等待知道指定的时间点到来:void f() { auto now=std::chrono::steady_clock::now(); test_mutex.try_lock_until(now + std::chrono::seconds(10)); std::cout << "hello world\n"; }
-
-
recursive_timed_mutex
其他
lock_guard类
一个类, 构造时需要传入一个mutex
, 构造的时候对其上锁, 析构的时候释放, 使用的时候只需要定义一个lock_guard
变量, 然后代码块结束的时候lock_guard
就会自动析构达到自动释放的目的:
void safe_increment()
{
std::lock_guard<std::mutex> lock(g_i_mutex);
++g_i;
std::cout << std::this_thread::get_id() << ": " << g_i << '\n';
// g_i_mutex is automatically released when lock
// goes out of scope
}
lock_guard
类还有一个构造函数, 可以提供一个lock tag
:
lock标记
defer_lock_t
: do not acquire ownership of the mutextry_to_lock_t
try to acquire ownership of the mutex without blockingadopt_lock_t
assume the calling thread already has ownership of the mutex
std::lock_guard<std::mutex> lock1(from.m, std::adopt_lock);
scoped_lock
构造函数可以传入多个互斥量
https://en.cppreference.com/w/cpp/thread/scoped_lock/scoped_lock
unique_lock
unique_lock
比lock_guard
更加灵活, 提供了try_lock
, lock_for
, lock_until
等接口, 析构时会根据锁的状态自动判断是否需要释放锁
unique_lock
只允许一个线程获取锁
提供了这些构造函数:
详见: https://en.cppreference.com/w/cpp/thread/unique_lock/unique_lock
unique_lock() noexcept;
unique_lock( unique_lock&& other ) noexcept;
explicit unique_lock( mutex_type& m );
unique_lock( mutex_type& m, std::defer_lock_t t ) noexcept;
unique_lock( mutex_type& m, std::try_to_lock_t t );
unique_lock( mutex_type& m, std::adopt_lock_t t );
template< class Rep, class Period >
unique_lock( mutex_type& m,
const std::chrono::duration<Rep,Period>& timeout_duration );
template< class Clock, class Duration >
unique_lock( mutex_type& m,
const std::chrono::time_point<Clock,Duration>& timeout_time );
共享锁, 用来解决读者写着问题, 可以被多个线程获取, 需要头文件shared_mutex
#include <shared_mutex>
#include <iostream>
#include <thread>
#include <chrono>
std::shared_timed_mutex m;
int i = 10;
void read()
{
// both the threads get access to the integer i
std::shared_lock<std::shared_timed_mutex> slk(m);
std::cout << "read i as " << i << "...\n"; // this is not synchronized
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::cout << "woke up...\n";
}
int main()
{
std::thread r1(read);
std::thread r2(read);
r1.join();
r2.join();
return 0;
}
lock和try_lock函数
函数可以传入多个互斥量并对其进行同时上锁, 使用死锁避免算法避免死锁
condition_value
头文件condition_variable
和Java和Python的差不多, 贴个例子:
https://en.cppreference.com/w/cpp/thread/condition_variable
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// Wait until main() sends data
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});
// after the wait, we own the lock.
std::cout << "Worker thread is processing data\n";
data += " after processing";
// Send data back to main()
processed = true;
std::cout << "Worker thread signals data processing completed\n";
// Manual unlocking is done before notifying, to avoid waking up
// the waiting thread only to block again (see notify_one for details)
lk.unlock();
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
data = "Example data";
// send data to the worker thread
{
std::lock_guard<std::mutex> lk(m);
ready = true;
std::cout << "main() signals data ready for processing\n";
}
cv.notify_one();
// wait for the worker
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return processed;});
}
std::cout << "Back in main(), data = " << data << '\n';
worker.join();
}