更多使用
参考:https://en.cppreference.com/w/
thread类
//一个常用的构造函数形式
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );//参数均为右值引用,其为临时对象不会影响原来的对象
//线程的函数参数必须是一个没有返回值的函数
简单使用
#include <thread>//包含线程头文件
#include <iostream>
thread_local int g_num = 1;//定义一个线程变量,对于线程变量,每个线程都会有该变量的一个拷贝,互不干扰。该局部变量一直都在,直到线程退出为止,线程变量在线程执行过程当中必须有效,如此处若在main函数中使用detach将线程置为分离态,main执行结束会销毁g_num变量
void thredfun1()
{
g_num++;
std::cout<<"thread1 no arg"<<std::endl;
std::cout<<"thread1 g_num: "<<g_num<<std::endl;
}
void thredfun2(int x,int y)
{
g_num++;
std::cout<<"thread2 arg:"<<x<<" "<<y<<std::endl;
std::cout<<"thread2 g_num: "<<g_num<<std::endl;
}
int main()
{
std::thread f1(thredfun1);
std::thread f2(thredfun2,2,3);
//f1.detach();
//f2.detach();//调用其使线程置为分离态,不用等待其执行结束后返回,若main函数比线程函数先执行结束,则不能在main函数中执行线程分离函数
f1.join();
f2.join();//等待线程结束后返回
std::cout<<"main end"<<std::endl;
return 0;
}
线程资源同步对象
std::mutex
互斥量 | 版本 | 作用 |
---|---|---|
mutex | C++11 | 最基本的互斥量 |
timed_mutex | C++11 | 有超时机制的互斥量 |
recursive_mutex | C++11 | 可重入的互斥量 |
recursive_timed_mutex | C++11 | 结合 timed_mutex 和 recursive_mutex 特点的互斥量 |
shared_timed_mutex | C++14 | 具有超时机制的可共享互斥量 |
shared_mutex | C++17 | 共享的互斥量 |
使用RAII技术对mutex的封装
互斥量管理 | 版本 | 作用 |
---|---|---|
lock_guard | C++11 | 基于作用域的互斥量管理 |
unique_lock | C++11 | 更加灵活的互斥量管理 |
shared_lock | C++14 | 共享互斥量的管理 |
scope_lock | C++17 | 多互斥量避免死锁的管理 |
使用RAII技术在类构造时调用锁的加锁函数,析构时调用函数的解锁函数,成员变量是一个锁的引用,大概为以下意思:
class RAII{
public :
RAII(mutex& t):mutex_(t){
mutex_.lock()
}
~RAII(){
mutex_.unlock();
}
private:
mutex& mutex_;
};
lock_guard使用示例:
{
std::lock_guard<std::mutex> guard(mutex_);//初始化并加锁,括号内为锁的作用范围
//在这里放被保护的资源操作
}
//出括号guard析构解锁
std::condition_variable
条件变量
void fun1()
{
std::unique_lock<std::mutex> guard(mymutex);
while ([true]or[flase])//此处不能使用if
{
//如果获得了互斥锁,但是条件不合适的话,pthread_cond_wait会释放锁,不往下执行。
//当发生变化后,条件合适,pthread_cond_wait将直接获得锁。
mycv.wait(guard);
}
}
void fun2()
{
//释放信号量,通知等待线程
mycv.notify_one();
}
虚假唤醒
变量的线程也有可能会醒来。我们将条件变量的这种行为称之为 虚假唤醒。因此将条件放在一个 while 循环中意味着光唤醒条件变量不行,还必须条件满足程序才能继续执行正常的逻辑。
另外一种系统调用被中断:pthread_cond_wait 是 futex 系统调用,属于阻塞型的系统调用,当系统调用被信号中断的时候,会返回 -1,并且把 errno 错误码置为EINTR。很多这种系统调用为了防止被信号中断都会重启系统调用(即再次调用一次这个函数)。但有的系统调用被中断可以系统自己重试,有的不可以重试的,不可以重试的需要调用者自己手动重试。此处使用while循环则相当于调用者自己重试。若不判断条件向下执行,则不符合代码逻辑,即当前条件不满足无法执行后续操作。若使用if则不会重新判断会直接向下执行,若条件不满足则有可能会引起程序的崩溃。
std::atomic
原子操作类
#include <atomic>
#include <iostream>
int main()
{
std::atomic<int> value;
value = 99;//atomic默认禁用拷贝构造函数,所以不不能使用 std::atomic<int> value = 99;但支持赋值操作
//atomic& operator=( const atomic& ) = delete;禁用拷贝构造函数
//T operator=( T desired );合法赋值
std::cout<<value<<std::endl;
//自增1,原子操作
value++;
std::cout<<value<<std::endl;
return 0;
}