什么是原语?
答:执行时不可中断的过程。
P操作P(s):将整形型号量s的值减去1,如果结果小于0,那么调用P(s)的进程,将进程的信号量s的等待状态。
V操作V(s):将整形信号量s的值减去1,如果结果大于0,那么释放一个等待信号量s的进程。
/* 关于P操作 */ void P(semaphore *s){ s->value = s->value - 1; if(s->value < 0){ insert(CALLER, s->PCB); /* 将调用进程插入到等待信号量s的进程队列中 */ block(CALLER); /* 堵塞调用进程 */ } }
/* 关于V操作 */ void V(semaphore *s){ PID proc_id; /* 执行的进行号 */ s->value = s->value + 1 if(s->value <= 0){ remove(s->PCB, &proc_id); /* 从等待信号量s的进程中摘除proc_id该进程 */ wakeup(proc_id); /* 唤醒该进程 */ } }
值得注意的是:pv执行时,唤醒的顺序是由系统决定,唤醒的顺序不会影响程序正确性。
PV操作实现进程同步的操作
执行步骤:
1.为各进程设置私有信号量;2.为私有信号量赋初值;3.根据pv操作以及私有信号量设置各进程的执行顺序。
那问题来了:什么是私有信号量?
答:私有信号量:各进程发送的用于控制进程同步的消息。公有信号量:用于进程的互斥信号量。
二者的区别:私有信号量只与制约和被制约的进程有关,与整组并发进程无关。
经典案列:现有m个生产者和n个消费者,它们共享可存放k件物品的缓冲区。
int buffer[k]; /* 设置缓冲区以及容量 */ semaphore s1, s2, s; /* 设置信号量:s1(当进程缓冲区满时,生产者不能往满的缓冲区执行放操作的信号量),s2(当进程的缓冲区空时,消费者不能往空的缓冲区执行取操作的信号量), s(生产者与消费者互斥的信号量) */ int in, out; /* 设置存储的操作(说白了就是存放的位置) */ /* 赋初值 */ s.value = 1; s1.value = k; s2.value = 0; Cobegin repeat produceri; /* 生产者的执行 */ repeat consumerj; /* 消费者的执行 */ Coend; /* 生产者进程 */ process produceri{ int item; 生产者存放一件产品到item中; P(&s1); /* 执行P操作,检查是否能够进行放操作 */ P(&s); /* 执行P操作,检查临界区是能能够进入 */ buffer[in] = item; /* 将产品放到buffer缓冲区中 */ in = (in + 1) % k; /* 往后移动一位 */ V(&s2); /* 执行V操作 */ V(&s); /* 执行V操作 */ } /* 消费者进程 */ process consumerj{ int item; P(&s2); /* 执行P操作,检查是否能够进行取操作 */ P(&s); /* 执行P操作,检查临界区是能能够进入 */ item = buffer[out]; /* 取一件产品 */ out = (out + 1) % k; V(&s1); V(&s); 消费产品; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现