C++11的std::thread
开门见山,cpp多线程使用方法就是使用C++11的thread进行多线程编程。
std::thread常用成员函数
构造&析构函数
| 函数 | 类别 | 作用 |
|---|---|---|
| thread() | 默认构造函数 | 创建一个线程 |
| thread(thread&& x) | 移动构造函数 | 构造一个与x相同的对象,会破环x对象 |
| ~thread() | 析构函数 | 析构对象 |
常用成员函数
| 函数 | 作用 |
|---|---|
| void join() | 等待线程结束并清理资源(会阻塞) |
| bool joinable() | 返回线程是否可以执行join函数 |
| void detach() | 将线程与调用其的线程分离,彼此独立执行(此函数必须在线程创建时立即调用,且调用此函数会使其不能被join) |
| std::thread::id_get_id | 获取线程id |
| thread& operator=(thread &&rhs) | 移动构造函数(如果对象是joinable的,那么会调用std::terminate) |
注意事项
- 线程是在thread对象被定义的时候开始执行的,而不是在调用join函数时才执行的,调用join函数只是阻塞等待线程结束并回收资源
- 分离的线程(执行过detach的线程)会在调用它的线程结束或自己结束时释放资源
- 线程会在函数运行后自动释放,不推荐利用其他方法强制结束线程,可能会因资源未释放而导致内存泄露。
- 没有执行join或detach的线程在程序结束时会引发异常
std::atomic和std::mutex
作用:多个线程需要操作同一个变量时,防止产生竞争与冲突
std::mutex
std::mutex是C++中最基本的互斥量,一个线程将mutex锁住时,其他的线程就不能操作mutex,直到这个线程将mutex解锁。
1 |
|
mutex的常用成员函数
| 函数 | 作用 |
|---|---|
| void lock() | 将mutex上锁。 如果mutex已经被其他线程上锁, 那么mutex已经被同一个线程锁住, 那么会产生死锁。 |
| void unlock() | 解锁mutex,释放其所有权。 如果有线程因为调用lock()不能上锁而被阻塞,则调用此函数会将mutex的主动权随机交给其中一个线程; 如果mutex不是被此线程上锁,那么会引发未定义的异常。 |
| bool try_lock() | 尝试将mutex上锁。 如果mutex未被上锁,则将其上锁并返回true; 如果mutex已被锁则返回false. |
std::atomic
由于每个thread都要循环地加锁、解锁,我们使用std::atomic来提高效率。
1 |
|
原子操作 是最小的且不可并行化的操作。
这就意味着即使是多线程,也要像同步进行一样同步操作atomic对象,从而省去了mutex上锁、解锁的时间消耗。