提供一个 P 操作可以对 sem 进行 -1 操作,当 sem < 0 时,当前线程进入阻塞等待状态
提供一个 V 操作对 sem 进行 +1 操作,当 sem < 0 时,唤醒一个线程
其中 p 操作和 v 操作都是原语,原语是完成某种功能且不被分割不被中断执行的操作序列,是可由硬件实现的原子操作。信号量的实现模型:
// 信号量数据模型// 共享资源数和等待资源的进程链表typedefstruct{int value;// 共享资源数目struct process * L;// 进程链表,记录等待该资源的进程} semaphore;// 信号量的封装操作// 对信号量数据模型的两个操作voidwait(semaphore S){// 这个就是 P 操作S.value--;if(S.value <0){ add this process to S.Lblock(S.L);// block 是阻塞原语,线程或进程进入阻塞状态,由os和硬件配合实现}}voidsignal(semaphore S){// 这个就是 V 操作S.value++;if(S.value <0){ remove this process from S.Lwakeup(S.L);// wakeup 是线程唤醒原语}}
以上配合起来就可以解决同步和互斥的问题。
解决互斥问题
可见,P1 和 P2 竞争 S,只有通过 P 操作的进程方可执行,另一个进程需要等待,这就实现了互斥执行。