如何使用信号量实现屏障

时间:2013-11-17 21:17:29

标签: c multithreading semaphore

我有以下问题需要解决:

考虑一个应用程序,其中有三种类型的线程:Calculus-A,Calculus-B和Finalization。每当线程类型Calculus-A结束时,它会调用例程endA(),它会立即返回。每当线程类型Calculus-B结束时,它会调用例程endB(),它会立即返回。 Finalization例程之类的线程调用wait(), 仅当它们已经完成两个Calculation-A线程和2个Calculation-B线程时才返回。换句话说,对于微积分-A的2个结论和微积分-B的2个结论,一个线程终结被允许继续。 3种类型的线程数量不确定。不知道线程调用的例程的顺序。线程完成按到达顺序回答。 使用信号量实现例程endA(),endB()和wait()。除了变量初始化之外,唯一可能的操作是P和V.不能接受繁忙等待的解决方案。

这是我的解决方案:

semaphore calcA = 2;
semaphore calcB = 2;
semaphore wait = -3;

void endA()
    {
        P(calcA);
        V(wait);
    }

void endB()
    {
        P(calcB);
        V(wait);
    }

void wait()
    {
        P(wait);
        P(wait);
        P(wait);
        P(wait);
        V(calcA);
        V(calcA);
        V(calcB);
        V(calcB);
    }

我相信由于等待初始化而导致死锁,if和wait()在endA()和endB()之前执行。还有其他解决办法吗?

1 个答案:

答案 0 :(得分:4)

我倾向于将信号量问题视为必须识别“等待来源”的问题,并为每个信号量及其访问协议定义。

考虑到这一点,“等待的来源”是

  • CalcA的完成
  • CalcB的完成
  • 也许,如果我理解这一点,等待整个完成组,包括两个CalcAs和两个CalcB。我说也许因为我不确定“线程完成是否按照到达顺序得到回答。”表示。

CalcA和CalcB的完成因此应增加其各自的计数器。在另一端,一个终结线程获得对计数器的独占访问权,并以任何顺序等待所需的完成次数构成完成组。然后它会解锁对下一组的访问权限。

我的代码如下,但由于我不熟悉荷兰语VP,我将使用take() / give()

semaphore calcA    = 0;
semaphore calcB    = 0;
semaphore groupSem = 1;

void endA(){
    give(calcA);
}

void endB(){
    give(calcB);
}

void wait(){
    take(groupSem);
    take(calcA);
    take(calcA);
    take(calcB);
    take(calcB);
    give(groupSem);
}

groupSem信号量确保全有或全无:进入临界区的线程将获得每个CalcA和CalcB的下两个完成。如果不存在groupSem,则输入wait的第一个线程可能需要两个As并阻塞,然后由另一个抓取两个As和两个B然后逃跑的线程接管。

如果groupSem不存在则存在一个更糟糕的问题,如果第二个线程采用两个As,一个B然后阻塞,然后第一个线程抓住第二个B.如果不知何故结果是finalization允许更多的CalculationA和CalculationB运行,然后你可能会遇到死锁,因为计算A和B的实例可能没有更多机会完成,因此最终化线程会挂起,无法生成更多的计算实例。