C++多线程基础学习笔记(五)
一、互斥量
1.1 互斥量的基本概念
简单来说,一个锁就是一个互斥量,既然是锁,就有两种状态:加锁和解锁,通过加锁>>>操作共享数据>>>解锁的方式,实现保护共享数据。
1.2 互斥量的用法
作用:在给某段代码加锁后,如果其他其他线程需要先等带该段代码执行完,然后解锁后才能继续执行。
头文件 :#include <mutex>
成员函数:lock() //加锁,unlock() //解锁
注意点:lock()与unlock()的使用必须成对存在。
1 #include <iostream> 2 #include <mutex> 3 using namespace std; 4 int num = 0; 5 mutex my_mutex; //创建一个互斥量 6 void print1() 7 { 8 for (int i = 0; i < 50; i++) 9 { 10 my_mutex.lock(); 11 cout << "thread_1:" << num++ << endl; 12 my_mutex.unlock(); 13 } 14 } 15 void print2() 16 { 17 for (int i = 0; i < 50; i++) 18 { 19 my_mutex.lock(); 20 cout << "thread_2:" << num++ << endl; 21 my_mutex.unlock(); 22 } 23 } 24 25 int main() 26 { 27 thread thread_1(print1); //打印0-49 28 thread thread_2(print2); //打印49-99 29 thread_1.join(); 30 thread_2.join(); 31 system("pause"); 32 return 0; 33 }
还有一种方法,可实现加锁和解锁两个步骤,即用std::lock_guard<mutex> myguard (my_mutex)来代替lock()和unlock(),其原理是,在std::lock_guard构造函数里执行了lock(),在析构函数里执行了unlock()。
1 #include <iostream> 2 #include <mutex> 3 using namespace std; 4 int num = 0; 5 mutex my_mutex; 6 void print1() 7 { 8 for (int i = 0; i < 50; i++) 9 { 10 lock_guard<mutex> myguard(my_mutex); 11 cout << "thread_1:" << num++ << endl; 12 } 13 } 14 void print2() 15 { 16 for (int i = 0; i < 50; i++) 17 { 18 lock_guard<mutex> myguard(my_mutex); 19 cout << "thread_2:" << num++ << endl; 20 } 21 } 22 23 int main() 24 { 25 thread thread_1(print1); //打印0-49 26 thread thread_2(print2); //打印49-99 27 thread_1.join(); 28 thread_2.join(); 29 system("pause"); 30 return 0; 31 }
二、死锁
仅在存在两个互斥量以上才会出现死锁的现象。例如线程A获得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都永远处于挂起状态了。通俗来讲,就是我在等你解锁我才能解锁,你在等我解锁你才能解锁。
1 #include <iostream> 2 #include <mutex> 3 using namespace std; 4 int num = 0; 5 mutex my_mutex1; 6 mutex my_mutex2; 7 void print1() 8 { 9 for (int i = 0; i < 500; i++) 10 { 11 my_mutex1.lock(); 12 /*这里同通常有一段代码,也是用来操作共享数据*/ 13 my_mutex2.lock(); 14 cout << "thread_1:" << num++ << endl; 15 my_mutex1.unlock(); 16 my_mutex2.unlock(); 17 } 18 } 19 void print2() 20 { 21 for (int i = 0; i < 500; i++) 22 { 23 my_mutex2.lock(); 24 my_mutex1.lock(); 25 cout << "thread_2:" << num++ << endl; 26 my_mutex1.unlock(); 27 my_mutex2.unlock(); 28 } 29 } 30 31 int main() 32 { 33 thread thread_1(print1); //打印0-49 34 thread thread_2(print2); //打印49-99 35 thread_1.join(); 36 thread_2.join(); 37 system("pause"); 38 return 0; 39 }
运行结果发现也不会出现任何奔溃出错现象,但是就一直卡在那里,不会继续运行下去了。
解决死锁的方法其实也很简单,只要保证互斥量加锁的顺序一致就可以了。或者使用std::lock(mutex1,mutex2),意思是给这两个互斥量同时上锁。