C++多线程
-
互斥量
lock()和unlock()要成对使用
lock_guard sbguard(myMutex);相当于使用了lock()和unlock()
lock_guard构造函数执行了mutex::lock();在作用域结束时,调用析构函数,执行mutex::unlock()
lock_guard加入adopt_lock后,在调用lock_guard的构造函数时,不再进行lock(),而且必须要先锁上;lock(myMutex1, myMutex2);//这个的好处就是不需要考虑解锁 lock_guard<mutex> sbguard(myMutex1, adopt_lock); lock_guard<mutex> sbguard1(myMutex2, adopt_lock);
std::lock(mutex1,mutex2……); 一次锁定多个互斥量(一般这种情况很少),用于处理多个互斥量;
-
unique_lock
unique_lock比lock_guard多出很多用法而且可以随时解锁,但是效率差一点(unique_lock默认情况下也是不需要自己加锁解锁);
unique_lock的第二个参数
std::adopt_lock:
表示这个互斥量已经被lock(),即不需要在构造函数中lock这个互斥量了。
std::try_to_lock:
尝试用mutex的lock()去锁定这个mutex,但如果没有锁定成功,会立即返回,不会阻塞在那里;
使用try_to_lock的原因是防止其他的线程锁定mutex太长时间,导致本线程一直阻塞在lock这个地方
owns_locks()方法判断是否拿到锁,如拿到返回true
std::defer_lock:
如果没有第二个参数就对mutex进行加锁,加上defer_lock是始化了一个没有加锁的mutex,不给它加锁的目的是以后可以调用unique_lock的一些方法
前提:不能提前lock
release()
mutex* ptx =
myUniLock.release();所有权由ptx接管,如果原来mutex对象处理加锁状态,就需要ptx在以后进行解锁了。
std::call_once():
函数模板,该函数的第一个参数为标记,第二个参数是一个函数名(如a())。
功能:能够保证函数a()只被调用一次。具备互斥量的能力,而且比互斥量消耗的资源更少,更高效。
call_once()需要与一个标记结合使用,这个标记为std::once_flag;其实once_flag是一个结构,call_once()就是通过标记来决定函数是否执行,调用成功后,就把标记设置为一种已调用状态。std::once_flag onceflag; std::call_once(onceflag, MyThread);
我认为call_once()和原子操作类似,原子操作就是在多线程中不会被打断的程序片段;原子操作比互斥量更胜一筹;原子操作一般都是指“不可分割的操作”,也就是说这种操作状态要么是完成的,要么是没完成的,不可能出现半完成状态。
一般atomic原子操作,针对++、–、&=、|=是支持的。其他的可能不支持;#include<iostream> #include<thread> #include<string> #include<vector> #include<list> #include<mutex> #include<future> using namespace std; //我们封装了一个类型为int的对象,像操作一个int类型变量一样来操作这个g_mycont std::atomic<int> g_mycont = 0; void mythread() { for (int i = 0; i < 1000000; i++) { //g_mycont++;//对应的操作是个原子操作(不会被打断) //g_mycont += 1; g_mycont = g_mycont + 1; //结果不对,不是原子操作 } } int main() { thread myobj(mythread); thread myobj2(mythread); myobj.join(); myobj2.join(); cout << "两个线程执行完毕,最终的g_mycont的结果是:" << g_mycont <<endl; return 0; }
std::atomic来代表原子操作,std::atomic是个模板。其实std::atomic这个东西是用来封装某一个类型的值的;多线程中一般用于计数,或者统计。
-
条件变量
condition_variable
第一个参数是一个锁,第二个参数是一个可调用对象。
如果第二个参数返回true,wait()直接返回进入下一步。
如果第二个参数返回false,那么wati()将解锁互斥量,并堵塞直到其他某个线程调用notify_one()成员函数为止。
如果wait()没有第二个参数,那么就和第二个参数返回true的效果一样。std::mutex mymutex; std::unique_lock<std::mutex> uniquelock(mymutex); std::condition_variable condition; condition.wait(uniquelock, [this] {if (!msgRecvQueue.empty()) return true; return false; }); condition.wait(uniquelock);
notify_one成员函数
其他线程调用notify_one()将通知一个线程的wait()的状态唤醒后,wait恢复工作,如果wait并没有堵塞,那么此时notify_one调用可能就没有效果。