问题
使用二进制信号量实现计数信号量,数据结构定义如下(可以根据需要进行修改)。
Counting Semaphore S has initial value val = K;
struct S{
int value; //init to K
Semaphore sem; //init to 0
}
思路
正常来说,对于计数信号量的wait()操作,我们需要对value进行自减(value–);对于signal()操作,我们需要对value进行自增(value++)。
注意原子性要求,在对value操作前需要先上锁,操作后再解锁。
可是对于特殊情况:计数信号量为0时,上述操作的wait()会出问题,因此引入一个waiting_count变量记录在wait()的进程数量。
此时signal() 操作将会把等待中的一个进程唤醒,让其继续运行(waiting_count --)。
解答
struct S{
int value = K;
int waiting_count = 0; //计数信号量为0时,在等待的进程个数
Semaphore mutex = 1; //对value或wc的修改进行原子化操作,初始化为1
Semaphore sem = 0; //表示计数信号量为0时,是否有signal信号
};
void wait(struct S it){
wait(it.mutex); //对临界区(数据 waiting_count \ value)修改前,先上锁
if(it.value == 0){
it.waiting_count ++; //在等待的进程个数++
signal(it.mutex); //对临界区(数据 waiting_count \ value)修改后再解锁
wait(it.sem); //等待一个进程signal()释放资源
}else{
it.value --; //计数信号量 --
signal(it.mutex); //对临界区(数据 waiting_count \ value)修改后再解锁
}
}
void signal(struct S it){
wait(it.mutex); //对临界区(数据 waiting_count \ value)修改前,先上锁
if(it.waiting_count > 0){
it.waiting_count --; //在等待的进程个数--
signal(it.sem); //释放一个资源
}else{
it.value ++; //如果计数信号量不为0,计数信号量 ++
}
signal(it.mutex); //对临界区(数据 waiting_count \ value)修改后再解锁
}