c-如何使用信号量实现屏障



我有以下问题需要解决:

考虑一个有三种类型线程的应用程序:Calculus-A、Calculus-B和Finalization。每当一个线程类型Calculus-a结束时,它就会调用例程endA(),后者会立即返回。每当一个线程类型Calculus-B结束时,它就会调用例程endB(),后者会立即返回。像Finalization例程这样的线程调用wait(),仅当它们已经完成两个计算-A线程和两个计算-B线程时才返回。换言之,对于微积分A的正好2个结论和微积分B的2个结论,允许一个线程Finalization继续。这三种类型的线程数量尚未确定。目前还不知道线程调用的例程的顺序。线程完成按到达顺序回答。使用信号量实现例程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()之前执行,将会出现死锁。对此有其他解决方案吗?

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

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

  • CalcA的完成
  • CalcB的完成
  • 如果我理解正确的话,也许,等待由两个CalcA和两个CalcB组成的完整完成组。我说可能是,因为我不确定"线程完成是按到达顺序回答的。"的意思

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

我的代码如下,但由于我不熟悉荷兰语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的第一个线程可以获取两个A并阻塞,然后被另一个获取两个As和两个B的线程接管,然后逃跑。

如果groupSem不存在,那么存在的一个更糟糕的问题是,如果第二个线程获取两个A,一个B,然后阻塞,然后第一个线程获取第二个B。如果最终确定的结果允许更多地运行CalculationA和CalculationB,那么您可能会出现死锁,因为计算A和B的实例可能没有更多的机会完成,因此,最终线程挂起,无法生成更多的计算实例。

最新更新