多线程
一,线程状态·
thread.join() -------------- 阻塞当前线程thread,直到thread执行完成;
thread.detach() ----------使得当前线程脱离主线程的控制,该线程的资源由后台进程回收资源;
thread.joinable() ---------- 判断线程是否可以join或者detach;
二,线程创建写法
普通函数作为线程参数
可调用对象作为线程参数-----例如一个类重载operator()
lambda做为线程参数
三,线程传参的坑
1,传递临时对象作为线程参数
参数传递时应该显示构造对象,而不是依靠编译器隐士类型转换 例如char* -> string
如果是一般数据类型建议使用值传递,因为有可能主线程早于子线程结束,导致内存失效
2,传递类对象作为线程参数
往线程入口函数传递类类型对象作为参数时不管是否以 引用接受,都一概采用复制对象的方式传递
所以当我们需要修改某个对象的时候一般需要使用 std::ref(); eg:std::thread m_thread(&A::func(),&a,1);
或者 std::ref(a);
互斥量
锁
void Push(){
mutex.lock();
//.........去干一些事
mutex2.lock();
}
void Pop(){
mutex2.lock();
//.....去干一些事
mutex.lock();
}
上面代码就是一个死锁案例,所以为了防止造成死锁,一般在加锁的时候要按顺序加锁。
1,lock函数模板
同时处理多个锁,解决加锁顺序问题而导致的死锁
2,lock_guard类模板
lock_guard<std::mutex> sbguard(m_mutex,std::adopt_lock); // 表示不要再次lock,只需要unlock即可,但前提是先锁住
3,unique_lock类模板
unique_lock<std::mutex> sbguard(m_mutex,std::adopt_lock); // 表示不要再次lock,只需要unlock即可,但前提是先锁住
unique_lock<std::mutex> sbguard(m_mutex,std::try_to_lock);//尝试进行加锁,即便没有加锁成功也会返回,但不能提前加锁
std::unique_lock<std::mutex> sbguard(m_mutex,std::try_to_lock);
//owns.lock() //判断是否为主动加锁
if(sbguard.owns_lock()){
//加锁成功
}else{
//没有加锁成功
}
unique_lock<std::mutex> sbguard(m_mutex,std::defer_lock); 初始化一个mutex,但是不加锁,如果提前加锁程会报异常
unique_lock的成员函数
1.lock(),unlock() --- unique_lock可以随时加锁解锁,但lock_guard不行;
2.try_lock(),尝试加锁,如果加锁成功返回true否则false;
3,release(),解除unique_lock()与mutext的关联。 eg:
//1.lock()
{
std::unique_lock<std::mutex> sbguard(mutex,std::defer_lock);
sbgurad.lock();
}
//2,try_lock()
{
std::unique_lock<std::mutex> sbguard(mutex,std::defer_lock); //不会阻塞
if(sbguard.try_lock() == true){
//拿到锁
}else{
//没有拿到锁
}
}
//3,release()
{
std::unique_lock<std::mutex> sbguard(mutex,std::defer_lock);
std::mutex* p_mtx = sbguard.release(); //现在这个锁就需要程序员自己管理
}
条件变量
condition_variable --是一个类,只能接受unique_lock,必须配合互斥量
condition_variable_any --是一个类,可以接受任意类型的锁
wait() ,wait_for(),wait_until(),notify_one(),notify_all(),
std::condition_variable m_cond;
/*.....
.......
*/
//消费者
while(true){
std::unique_lock<std::mutex> sbgurad(mutex);
m_cond.wait(sbguard,[]{return false}) // or return true;
//..........
}
//生产者
for(int i = 0; i < 100; ++i){
std::unique_lock<std::mutex> sbgurad(mutex);
queue.push_back(i);
m_cond.notify_one();
}
1,如果第二个参数为true,则wait直接返回
2,如果第二个参数为false,则wait解锁互斥量并堵塞直到另一个线程调用notify_one()
3,如果第二个参数为空,相当于false
4,notify_one() 通知某一个线程,notify_all()通知所有线程
5,wait_for(mutex,std::chrono::duration<rep,den>) 当线程被通知或者超出时间段之后wait_for()返回
5,wait_until()到达某个时间点或者被通知wait_until()返回
6, cv.wait_for(mutex,std::chrono::seconds(1) == std::cv_status::timeout),通过cv_status来判断是否超时
7, 为了防止虚假唤醒,务必做判断