在多线程程序中,往往会遇到线程中资源同步问题,同步问题可以划分为两类,一类为共享一个资源,一类为给每个线程分配一个资源
一:给每个线程分配一个资源
1:定义线程变量,在变量名前面加上_thread,该变量就会申明为线程变量
但是同时C++中对__thread变量的使用有额外的限制:
1. 在C++中,如果要在定义一个thread-local变量的时候做初始化,初始化的值必须是一个常量表达式。
2. __thread只能修饰POD类型,即不带自定义的构造、拷贝、赋值、析构的类型,不能有non-static的protected或private成员,没有基类和虚函数,因此对定义class做了很多限制。但可以改为修饰class指针类型便无需考虑此限制。
2:当线程变量是复杂的C++类变量时,即不能申明为_thread变量
线程变量对于其他线程是可见,同时我们可以延伸出例外一种方式来代替线程变量
ps:A是一个类,线程的数量为n
A a[n];
对每个线程映射一个ID,线程1只能访问a[1],线程2访问a[2],从而达到每个线程访问一个对应的一个线程变量
二:多个线程共享一个资源
多个线程共享一个资源涉及多种方式:信号量,互斥量,临界区,自旋锁,读写锁,条件变量
1:信号量
信号量主要用于同步,信号量在系统中可以被任意一个线程释放
三个操作:
1、一个信号量可以初始化为非负值
2、semWait操作可以使信号量减1,若信号量的值为负,则执行semWait的进程被阻塞。否则进程继续执行。
3、semSignal操作使信号量加1。若信号量的值小于等于0,则被semWait操作阻塞的进程讲被接触阻塞。
ps: semWait对应P原语,semSignal对应V原语。
即A线程调用 semWait,B线程调用semSignal,可以释放A线程,让A线程执行
2:互斥量
互斥量主要用于防止多个线程同时访问同一个资源
A线程加锁了,B线程无法释放A线程加的锁,只能等A线程自己释放
3:临界区
在多进程程序中,临界区申明的锁,只对当前进程有效,其他进程无效,信号量跟互斥锁对其他进程也是有效的,可以获取的
4:自旋锁
自旋锁加锁时不会让出cpu,一直会处于自旋状态去获取锁,互斥量跟临界区都是会进入休眠状态,把CPU让出,自旋锁适用高性能场景
5:读写锁
当线程A处于读的状态,线程B也可以读,但是不能写,当线程A处于写的状态,线程B则不能读,适用与少写多读的场景
6:条件变量
条件变量可以同时唤醒多个线程,信号量只能唤醒一个,唤醒多个线程的时候,通常涉及到资源竞争,往往配合互斥锁使用