在代码中使用二进制信号量

Posted

技术标签:

【中文标题】在代码中使用二进制信号量【英文标题】:Use of binary semaphore in the code 【发布时间】:2018-04-17 22:33:27 【问题描述】:

某个计算生成两个数组ab,使得a[i]=f(i) for 0 ≤ i < n and b[i] = g(a[i]) for 0 ≤ i < n。假设这个计算被分解成两个并发进程XY,这样X计算数组aY计算数组b。这些进程使用两个二进制信号量RS,都初始化为零。数组a 由两个进程共享。进程的结构如下所示。

Process X:                         
private i;                         
for (i=0; i < n; i++)             
    a[i] = f(i);                       
    ExitX(R, S);                       
                                  

Process Y:
private i;
for (i=0; i < n; i++) 
    EntryY(R, S);
    b[i]=g(a[i]);

以下哪一项代表ExitXEntryY 的正确实现?

(A)

ExitX(R, S) 
    P(R);
    V(S);


EntryY (R, S) 
    P(S);
    V(R);

(B)

ExitX(R, S) 
    V(R);
    V(S);


EntryY(R, S) 
    P(R);
    P(S);

(C)

ExitX(R, S) 
    P(S);
    V(R);


EntryY(R, S) 
    V(S);
    P(R);

(D)

ExitX(R, S) 
    V(R);
    P(S);

EntryY(R, S) 
    V(S);
    P(R);

我认为答案应该是 (B),因为进程 Y 中的关键部分在 X 中的关键部分被执行之前不应执行(a[i] 首先被填充,这将必须用于b[i]),所以在执行X 之后,根据Y 中临界区入口处的选项(B)我们会找到R=1S=1,所以现在临界区在Y可以执行。

问题:正确答案是(C),我哪里错了?

【问题讨论】:

B 折叠了两把锁,所以它不可能是正确的。这里的重点是协调两个循环。让我写下来。 【参考方案1】:

'B' 如果它们不是二进制信号量,则可以工作:在这种情况下,X 可以创建一个元素,增加一个信号量,而 Y 可以等待该信号量并使用这些项目。信号量可以计算有多少项目可供处理。一个信号量就足够了。

但是你有二进制信号量。所以你最多只能数一个,例如X 可以创建一个元素,向信号量发出信号,但随后不能继续创建元素,因为它不能将该信号量值提高到“2”(或更多)。所以它必须等待那个单个元素被 Y 识别。并且这个等待引入了第二个信号量,当当前元素被处理时向 X 发出信号。重要的是要记住,P 会在必要时等待信号量增加(而 V 会增加),因此 X 不能等待单个信号量回到 0,因为没有这样的操作。

这就是“C”正在做的事情,S 实际上是“数据准备就绪”信号,R 是“确认”。 X 说,它准备好了,然后等待确认。 Y 等待就绪并发送确认。

【讨论】:

【参考方案2】:

首先,考虑一下为什么我们在这里甚至需要两个信号量。原因是我们这里有两件事要协调,

    在 X 循环完成之前,Y 循环无法启动 i i X 循环无法在 Y 完成 i 之前启动 i+1

所以有两个信号量,每个信号量在上面管理一个点。

信号量达到 1 需要从 ExitX 调用 P。而EntryY 需要拨打V。所以B已经不在了。要实现 2,我们需要 V in ExitXP in EntryY

所以看看A,没有人增加任何东西,所以这是一个死锁。

C 完成这项工作。

D 不太正确,因为 XY 可能会在调用该信号量的任何 P 之前两次命中 V

【讨论】:

这里的函数 ExitX 和 EntryY 被认为是原子的,对吧? @chunky 不,不是。只有 PV 是原子的。 这里ExitX执行的那一刻,信号量的更新值为S=0 , R=1,所以现在根据option (C)中的EntryY控制到达并执行,process Y中的b[i]=g(a[i]),现在更新的信号量值为S=1 , R=0,这确保a[i] = f(i)process X 中再次运行,对吧? @chun 没有。 ExitX 会阻塞,因为 S 最初是 0。所以 EntryY 需要先走。 但同样R也是0,那么EntryY怎么能先走呢?

以上是关于在代码中使用二进制信号量的主要内容,如果未能解决你的问题,请参考以下文章

数字信号和模拟信号之间如何让相互转换?

Java 监视器而不是二进制信号量

条件变量与信号量

在 C 语言中使用 POSIX 在多个进程(不是线程,仅进程)之间共享二进制信号量

使用二进制信号量用餐哲学家

使用互斥锁和条件变量而不是信号量在 c++14 中打印从 1 到 10 的数字?