信号量同步互斥问题

一、信号量

信号量是一种抽象数据类型

  1. 由一个整型(sem)变量和两个原子操作组成
  2. P():sem减1,如果sem<0进入等待状态,否则继续
  3. V():sem加1,如果sem<=0则唤醒一个等待的线程
    这里写图片描述

二、管程

管程是一种用于多线程互斥访问共享资源的程序结构

  1. 局部数据变量只能被管程的过程访问,任何外部过程都不能访问
  2. 一个进程通过调用管程的一个过程进入管程
  3. 在任何时候,只能有一个进程在管程中执行,调用管程的任何其他进程都被阻塞,以等待管程可用

管程的使用

  1. 管理共享数据
  2. 定义访问共享数据的方法

这里写图片描述
条件变量

  1. 条件变量是管程内的等待机制
    1.1. 进入管程的线程因资源被占用而进入等待状态
    1.2. 每个条件变量表示一种等待原因,对应一个等待队列
  2. Wait()操作
    2.1. 将自己阻塞在等待队列中
    2.2. 放弃对管程的互斥访问权限(同一时刻管程只能有一个进程访问)
  3. Signal()操作
    3.1. 将等待队列中的一个线程唤醒(信号量机制中的Signal是释放一个信号量,如果信号量≤0则唤醒一个线程)

三、生产者消费者问题

这里写图片描述
①生产者在生成数据后放在一个缓冲区里
②消费者从缓冲区中读取数据
③任何时刻只能有一个生产者或消费者可以访问缓冲区

问题分析:
①任何时刻只能有一个线程操作缓冲区
②缓冲区满时,生产者要等待消费者
③缓冲区空时,消费者要等待生产者

利用信号量解决
这里写图片描述

利用管程解决
这里写图片描述

四、哲学家就餐问题

问题描述
这里写图片描述

解决方案
这里写图片描述
这里写图片描述
这里写图片描述

五、读者-写者问题

这里写图片描述

管程的状态变量
这里写图片描述

  • AR:正在读的读者数量
  • AW:正在写的写者数量
  • WR:等待读的读者数量
  • WW:等待写的写者数量
  • okToRead:读者的等待队列
  • okToWrite:写者的等待队列

读者模块(写者优先)
这里写图片描述
startRead():如果有写者正在写或等待写,则进入等待队列
DoneRead():如果没有读者在读且有写者等待写,则唤醒写者

写者模块(写者优先)
这里写图片描述
StartWrite():如果有读者在读或有写者在写,则进入等待队列
DoneWrite():如果有写者等待写,则优先唤醒写者,或者唤醒等待的读者

  • 7
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 POSIX 信号量进行进程间同步可以分为以下几个步骤: 1. 创建信号量:使用 `sem_open` 函数创建一个新的信号量或打开一个已经存在的信号量。 ```c #include <semaphore.h> sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value); ``` 其中,`name` 参数为信号量的名称,`oflag` 参数指定打开或创建标志,`mode` 参数指定权限位,`value` 参数指定信号量的初始值。若成功返回一个指向信号量对象的指针,否则返回 `SEM_FAILED`。 2. 进程等待信号量:使用 `sem_wait` 函数等待信号量。若信号量的值大于 0,`sem_wait` 函数会将信号量值减 1 并立即返回;否则,它会阻塞进程直到信号量可用。 ```c #include <semaphore.h> int sem_wait(sem_t *sem); ``` 其中,`sem` 参数为指向信号量对象的指针。若成功返回 0,否则返回 -1。 3. 进程释放信号量:使用 `sem_post` 函数释放信号量。`sem_post` 函数将信号量值加 1,并唤醒一个等待的进程。 ```c #include <semaphore.h> int sem_post(sem_t *sem); ``` 其中,`sem` 参数为指向信号量对象的指针。若成功返回 0,否则返回 -1。 4. 关闭信号量:使用 `sem_close` 函数关闭一个打开的信号量。 ```c #include <semaphore.h> int sem_close(sem_t *sem); ``` 其中,`sem` 参数为指向信号量对象的指针。若成功返回 0,否则返回 -1。 下面是一个简单的示例: ```c #include <stdio.h> #include <stdlib.h> #include <semaphore.h> #include <fcntl.h> #include <unistd.h> int main() { sem_t *sem = sem_open("my_semaphore", O_CREAT, 0644, 1); if (sem == SEM_FAILED) { perror("sem_open"); exit(EXIT_FAILURE); } pid_t pid = fork(); if (pid < 0) { perror("fork"); exit(EXIT_FAILURE); } else if (pid == 0) { // 子进程 sem_wait(sem); printf("Child process: got the semaphore\n"); sem_post(sem); exit(EXIT_SUCCESS); } else { // 父进程 sem_wait(sem); printf("Parent process: got the semaphore\n"); sem_post(sem); wait(NULL); sem_close(sem); sem_unlink("my_semaphore"); exit(EXIT_SUCCESS); } } ``` 在这个示例中,我们创建了一个名为 `my_semaphore` 的信号量,并将其初始值设置为 1。然后创建了一个子进程,父进程和子进程都调用了 `sem_wait` 函数等待信号量。 由于初始值为 1,因此父进程可以先获取到信号量,输出 "Parent process: got the semaphore",然后释放信号量并等待子进程结束。子进程在父进程释放信号量后获取信号量,输出 "Child process: got the semaphore",然后释放信号量并退出。最后父进程关闭信号量并删除对应的信号量对象。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值