线程/进程间同步

1、竞争条件
两个或多个进程/线程读写某些共享数据时,结果取决于其CPU调度的运行次序,这种现象称为竞争条件
2、互斥
以某种手段确保当一个进程/线程在使用一个共享变量或文件时,其他进程/线程不能做同样的操作
3、临界区
把对共享内存进行访问的程序片段称为临界区,如果能使得两个进程/线程不同时处于临界区,就能够避免竞争条件
4、几种互斥方案

屏蔽中断、原子操作、锁、自旋锁、多元信号量(又名信号量)、二元信号量、读写锁、互斥量、条件变量

1)屏蔽中断
在单处理器中,使每个进程刚进入临界区后就立即屏蔽中断,在就要离开临界区之前再打开中断,屏蔽中断之后,时钟中断也会被屏蔽,由于CPU只有在发生时中中断或其他中断时才会进行进程切换,这样,在屏蔽中断之后,CPU将不会被切换到其他进程,因此此时不必担心其他进程介入
存在的问题:多核无效、
2)锁
一种软件解决方案,使用一个共享锁变量,初始值设为0,每个进程进入临界区以前先访问该锁变量,检查其值是否为0
存在的问题:在一个进程访问到值为0 ,并将其修改为1之前,另一个进程可能会访问到其值为0,因为这个操作不是原子的
3)严格轮换法(自旋锁)
Thread1:
while( true){
    while(turn!= 0);
    critical_region();
    turn= 1;
    noncritical_region();
}
Thread2:
while( true){
    while(turn!= 1);
    critical_region();
    turn= 0;
    noncritical_region();
}
如上述代码所示:线程2会连续测试变量turn直到其值为1,这称为忙等待,用于忙等待的锁称为自旋锁。
存在的问题:解决了2)中的问题,但是这种忙等待很浪费CPU时间,而且如果线程1 sleep,会导致线程2一直循环
4)原子操作
原子操作即是指一组相关的操作要么都不间断的执行,要么都不执行
原子操作:单指令操作,在程序的执行过程中,单指令操作不会被打断,而对于非原子操作:比如++i(首先读取i到某个寄存器X;然后执行X++;最后将X的内容存储回i),由于其任何一部都有可能被打断,因此不是线程安全的。在Windows上,有一套API专门进行原子操作,比如:InterlockedExchange:原子地交换两个值;InterlockedDecrement:原子地减少一个值;InterlockedIncrement:原子地增加一个值...。然而,有一个问题是,对于复杂的数据结构或者操作,我们并不能很容易甚至不能实现原子操作,因此,为了保证线程安全,我们还需要其他的线程同步机制。
5)(多元)信号量
多元信号量,顾名思义,可以允许多个线程并发访问资源,一个初始值为N的信号量允许N个线程并发访问,线程通过信号量访问资源时会执行如下操作:
1)将信号量减1;
2)如果信号量的值<0,则进入等待状态,否则访问资源;
3)访问资源结束以后,线程释放信号量,即将信号量的值加1;
4)如果信号量的值小于1,唤醒一个等待中的线程。
6)二元信号量
二元信号量是最简单的一种锁,只有两种状态:占用与非占用。二元信号量适用于只能被一个线程所访问的数据或资源。当二元信号量处于非占用状态时,第一个试图该二元信号量的线程会获得该锁(二元信号量);当其为占用状态时,任何试图获取该二元信号量的线程都必须等待指导该二元信号量被释放。
7)互斥量
互斥量的作用与二元信号量相同,区别在于:同一个信号量可以被系统中的一个线程获取之后由另一个线程释放(因为信号量其实就是一个计数机制,任何线程都可以更改这个计数值,计数值减为0,即该锁释放),而互斥量要求线程的获取和释放必须由同一个线程进行,其他线程无法释放互斥量
互斥量常和条件变量一起使用、互斥量是一个可以处于两态之一的变量:解锁和加锁,0表示解锁,其他所有值均表示加锁
pthread中的互斥量mutex
函数调用:
pthread_mutex_t mutex
pthread_mutex_init:创建一个互斥量
pthread_mutex_destory:撤销一个已经存在的互斥量
pthread_mutex_lock:获得一个锁/加锁,若失败则阻塞
pthread_mutex_trylock:加锁,若失败则返回一个错误,不会阻塞
pthread_mutex_unlock:释放锁
8)条件变量
使用条件变量可以让多个线程一起等待某个事件的发生,当事件发生即条件变量被唤醒时,所有线程可以一起恢复执行。
条件变量不是计数器,条件变量也不能像信号量那样积累信号以便以后使用。所以,如果向一个条件变量发送信号,但是在该条件变量上并没有等待进程,则该信号会永远丢失,也就是说,wait操作必须在signal操作之前
例如条件变量和互斥量结合解决生产者消费者问题
pthread_cond_t condc
pthread_cond_init:创建一个条件变量
pthread_cond_destroy:撤销一个条件变量
pthread_cond_wait:阻塞以等待一个信号
pthread_cond_signal:向另一个线程发起一个信号来唤醒它
pthread_cond_broadcast:向多个线程发起信号来让它们全部唤醒
9)读写锁
对于共享资源的操作无外乎就是读取与重写,读取不会引起线程同步问题,只有写操作才会带来线程同步问题,因此,对于读取操作远远频繁与写操作的情况,上述同步机制会显得十分低效。因此,引入了读写锁。读写锁有三种状态:自由、共享、独占。有两种获取方式:以共享方式获取、以独占方式获取。自由状态下,两种方式均可获取该锁;共享状态下,可以共享方式获取该锁,如果以独占方式获取该锁必须等待,直到所有使用该锁的线程释放锁;独占状态下,两种获取方式均需要等待。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值