利用信号解决竞争条件

在父进程调用fork创建了子进程后,父进程和子进程可能都有一些事情要做。例如,父进程需用子进程ID更新日志,子进程可能需要为父进程创建一个文件。fork后哪一个进程会先被调度执行是未知的,因此便会产生竞争条件。

#include"apue.h"
TELL_WAIT();//set things up for TELL_XXX and WAIT_XXX
if((pid=fork())<0)
{
        err_sys("fork error!");
}
else if(pid==0)
{
        /*child process does whatever is necessary*/
        
        TELL_PARENT(getppid());//tell parent we are done
        WAIT_PARENT();//wait for parent
        
        /*and the child continues on its way*/
        
        exit(0);
}
/*parent does whatever is necessary*/

TELL_CHILD(pid);//tell child we are done
WAIT_CHILD();//wait for child;

/*and the parent continues on its way*/
exit(0);

图中,fork之后花开两朵,两个进程各自做自己的事情,但是两个进程完成若想完成后面的工作,则对另一进程有所依赖。例如只有当子进程创建了文件之后父进程才能继续后面的工作,或者是只有当父进程更新完日志之后子进程才能进行后面的工作,为达到这个目的,需要两个进程之间相互协调,即进程间通信(IPC)。IPC的具体实现方式有多种,这里用信号的方式实现如下。

#include"apue.h"
#include<signal.h>

static volatile sig_atomic_t sigfla
### 使用信号解决操作系统中的生产者消费者问题 #### 生产者-消费者问题概述 生产者-消费者问题是经典的多线程同步问题之一,描述了一个场景,其中生产者线程负责生成数据,消费者线程负责处理数据,而两者通过一个缓冲区进行交互[^2]。 #### 信号量的作用 信号量是一种用于控制访问共享资源的机制。它可以用来管理并发程序中多个线程之间的互斥和同步。对于生产者-消费者问题而言,可以利用两个计数型信号量 `empty` 和 `full` 来分别表示可用空间的数量和已存入项目的数量;另外还需要一个二元信号量 `mutex` 实现临界区保护[^1]。 #### 解决方案设计 为了防止竞争条件的发生并确保系统的正常运作,当有新的项目要放入队列时,应先检查是否有足够的空位(`empty`);而在取出项之前则需确认当前存在可取物品 (`full`). 同样地,在执行上述任一动作前都得获取对应的锁(`mutex`), 完成后再释放它以便其他进程能够继续工作. 具体来说: - **初始化阶段** - 设定初始状态下的三个信号量分别为:`empty=n`, 表示缓冲区内全部位置均为空闲; `full=0`, 显示没有任何产品存在于缓存之中; `mutex=1`, 确保同一时刻只有一个实体能修改内部结构。 - **生产者的操作流程** - 尝试减少 `empty` 的值 (P(empty)) , 如果失败说明此时没有剩余的空间可供存储新产生的货物, 那么这个过程会被阻塞直到有足够的空间为止. - 获取 `mutex` 锁(P(mutex)), 进入临界区域开始写入数据至缓冲池内某处. - 增加 `full` 计数值(V(full)). - 释放 `mutex` 锁(V(mutex)) 结束本次循环准备下一轮制造活动. - **消费者的行动模式** - 减少 `full` 数字(P(full)), 若发现里面已经没有任何东西了就会暂停下来等候补给. - 把握住 `mutex` 控制权(P(mutex)) 执行读取消息的动作. - 提升 `empty` 变量所代表的位置数目(V(empty)). - 放开 `mutex` 授权他人使用公共资源. 以下是基于 Python 编写的伪代码展示如何运用信号量来协调生产和消费行为: ```python import threading from collections import deque class ProducerConsumerProblem: def __init__(self, size): self.buffer = deque(maxlen=size) self.empty = threading.Semaphore(size) self.full = threading.Semaphore(0) self.mutex = threading.Lock() def produce(self,item): self.empty.acquire() with self.mutex: self.buffer.append(item) print(f'Produced {item}') self.full.release() def consume(self): self.full.acquire() with self.mutex: item=self.buffer.popleft() print(f'Consumed {item}') self.empty.release() if __name__=='__main__': pc_problem = ProducerConsumerProblem(5) producer_thread = threading.Thread(target=lambda:pc_problem.produce('data')) consumer_thread = threading.Thread(target=pc_problem.consume) producer_thread.start();consumer_thread.start(); ``` 这段代码定义了一个类 `ProducerConsumerProblem` ,实现了带有固定长度的最大容量限制的双端队列作为缓冲器,并创建了相应的信号量对象来进行同步控制。此外还提供了简单的测试函数以启动单个生产者和消费者线程实例化演示整个逻辑框架的工作方式.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值