操作系统一般都会有
思路大同小异
注:
临界区和互斥锁的区别
1、临界区只能用于对象在同一进程里线程间的互斥访问;互斥体可以用于对象进程间或线程间的互斥访问。
2、临界区是非内核对象,只在用户态进行锁操作,速度快;互斥体是内核对象,在核心态进行锁操作,速度慢。
3、临界区和互斥体在Windows平台都下可用;Linux下只有互斥体可用

1.Mutex 互斥量/互斥锁

(1)互斥访问(只能被一个任务访问)、 =>主要功能
目的是:资源保护(如一段代码,全局变量)
(2)任务同步
任务1控制温度、任务2控制电机 => 独立的
任务1温度、任务2电机 => 温度高于多少,电机开始转动
温度在合理范围,则电机挂起
温度高,唤醒电机转动
(3)多个任务的等待和唤醒排队机制
借一本书,后面有人排队在借,后面在等待,互斥锁会提供该机制

转载:
Mutex本质上说就是一把锁,提供对资源的独占访问,所以Mutex的主要作用是用于互斥的访问共享资源。
Mutex对象的值,只有0和1两个值。这两个值也分别代表了Mutex的两种状态。
值为0,表示锁定状态,当前对象被锁定,用户进程/线程如果试图Lock临界资源,则进入排队等待。
值为1,表示空闲状态,当前对象为空闲,用户进程/线程可以Lock临界资源,之后Mutex值减1变为0.
Mutex可以被抽象为四个操作:创建 Create;加锁 Lock;解锁 Unlock;销毁 Destroy。
Mutex被创建时可以有初始值,表示Mutex被创建后,是锁定状态还是空闲状态。
在同一个线程中,为了防止死锁,系统不允许连续两次对Mutex加锁。就是加锁和解锁这两个对应的操作,需要在同一个线程中完成。

避免互斥锁死锁的几个基本原则:
— 对共享资源操作前一定要获得锁。
— 完成操作以后一定要释放锁。
— 尽量短时间的占用锁,即占用锁的时间不要过长。
— 如果有多锁,如获得顺序是ABC连环扣,释放顺序也应该是ABC。
— 线程错误返回时应该释放它所获得的锁。

“挂起等待”和“唤醒等待线程”的操作?

每个Mutex有一个等待队列,一个线程要在Mutex上挂起等待,首先把自己加入等待队列中,然后置线程状态为睡眠,然后调用调度器函数切换到别的线程。一个线程要唤醒等待队列中的其它线程,只需从等待队列中取出一项,把它的状态从睡眠改为就绪,加入就绪队列,那么下次调度器函数执行时就有可能切换到被唤醒的线程。

一般情况下,如果同一个线程先后两次调用lock,在第二次调用时,由于锁已经被占用,该线程会挂起等待别的线程释放锁,然而锁正是被自己占用着的,该线程又被挂起而没有机会释放锁,因此就永远处于挂起等待状态了,这叫做死锁(Deadlock)。

另一种典型的死锁情形是这样:线程A获得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和线程B都永远处于挂起状态了。如果涉及更多的线程和更多的锁,则死锁的可能性更大。(例子,上厕所,要锁厕所门)

2.信号量

https://blog.csdn.net/ljianhui/article/details/10243617 信号量的不同进程互斥
https://blog.csdn.net/ljianhui/article/details/10813469 信号量不同线程的同步
信号量和互斥锁:差别是资源的多少
互斥锁是借一本书,只有一本书
一本书一共有三本,ABC可以借一本
因此说:互斥锁是信号量的一种形式
(1)多资源的互斥访问
(2)图书馆借书案例
锁是服务于共享资源的;而semaphore是服务于多个线程间的执行的逻辑顺序的。

转载:
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,它负责协调各个线程,以保证它们能够正确、合理的使用公共资源。信号量可以分为几类:
信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在哪里)。
而互斥锁是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这个资源。比如对全局变量的访问,有时要加锁,操作完了,在解锁。有的时候锁和信号量会同时使用的”

— 二进制信号量(binary semaphore):只允许信号量取0或1值,其同时只能被一个线程获取。

— 整型信号量(integer semaphore):信号量取值是整数,它可以被多个线程同时获得,直到信号量的值变为0.

— 记录型信号量(record semaphore):每个信号量s除一个整数值value(计数)外,还有一个等待队列List,其中是阻塞在该信号量的各个线程的标识。当信号量被释放一个,值被加1后,系统自动从等待队列中唤醒一个等待中的线程,让其获得信号量,同时信号量再减1.

信号量通过一个计数器控制对共享资源的访问,信号量的值是一个非负整数,所有通过它的线程都会将该整数减1.如果计数器大于0,则访问被允许;如果为0,则访问被禁止,所有试图通过它的线程都将处于等待状态。

计数器计算的结果是允许访问共享资源的通行证。因此,为了访问共享资源,线程必须从信号量得到通行证,如果该信号量的计数大于0,则此线程获得一个通行证,这将导致信号量的计数递减,否则,此线程将阻塞直到获得一个通行证为止。

当此线程不再需要访问共享资源时,它释放该通行证,这导致信号量的计数递增,如果另一个线程等待通行证,则那个线程将在那时获得通行证。
Semaphore可以被抽象为5个操作:
>> 创建 Create
>> 等待 Wait,线程等待信号量,如果值>0,则获得,值减1;如果<=0,则线程进入睡眠状态,直到信号量值>0或超时。
>> 释放 Post,执行释放信号量,则值加+1,如果此时有正在等待的线程,则唤醒该线程。
>> 试图等待 TryWait,线程并不真正的去获得信号量,而是检查信号量是否能够被获得,如果信号量值大于0,则TryWait返回成功,否则返回失败。
>> 销毁 Destroy
信号量,是可以用来保护两个或多个关键代码段,这些关键代码段不能并发调用。在进入一个关键代码段之前,线程必须获取一个信号量。首先要创建一个信号量,然后将Acquire Semaphore 以及Release Semaphore分别放置在每个关键代码段的首末段。

版权声明:本文为CSDN博主「cany1000」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dongyanxia1000/article/details/80433536

3.互斥量和信号量的区别:

互斥量用于线程的互斥,信号量用于线程的同步。

这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排他性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况下允许多个访问者同时访问资源。

互斥量值只能是0/1,信号量值可以为非负整数。

也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量时,也可以完成一个资源的互斥访问。

互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到。

————————————————
版权声明:本文为CSDN博主「cany1000」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dongyanxia1000/article/details/80433536

http://www.360doc.com/content/18/0424/15/44422250_748373742.shtml

4.互斥锁中的优先级翻转

低优先级的拿到信号量
高优先级抢占
因为低优先级已经有了->高优先级会等待->中等优先级运行

解决方法:
1.优先级天花板法,提高到能访问该资源的任务的最高的优先级 源码中的pip
2.继承法:A申请的时候,资源被C使用,通过比较C与自身的优先级,如果任务C的优先级小于自身的优先级,则将任务C提升到自身的优先级,任务C释放资源化。 ucos2不支持

ucos:两种方法的混合,直接提升到最高,即天花板