信号量实施

我想知道是否有办法在C ++(或C#)中实现信号量,任何有帮助的库。 我尝试使用OpenMP,但我无法实际阻止线程,而是我不得不忙着等待,如果/当我没有足够数量的线程时会导致死锁。 首先,我正在寻找一个可以让我阻止/生成/杀死我的线程的库。
其次,有没有已经实现信号量的库?
最后,当我被介绍到信号量的上下文时,我发现它非常有用(也许我错了?)但我没有看到很多库(如果有的话)实现它。 我熟悉OpenMP,环顾英特尔的TBB,C#线程。 但是在这些中我都没有明确地看到信号量。 那些信号量不像我想的那么实用吗? 还是他们难以实施? 还是我没有意识到?
PS
信号量可以跨平台实现吗? 因为它们可能与操作系统有关。

是否有任何库已经实现了这个?
对于C ++,有多个multithreading库,它们提供Semaphore实现:

  • POSIX
  • Poco线程
  • 小线程

此外,您还可以使用Boost实现信号量。 看看这个 。

第一个建议使用提升。 所有艰苦的工作都已完成。

如果你想看看它是如何实现的,它应该看起来像这样(虽然这是一个粗略的草图我相信一些研究可以优化)。 基本上信号量是由三件事构成的:

  • 伯爵
  • 条件变量(提供暂停)
  • 一个互斥体,提供修改计数和等待条件的排他性。

这是简单的版本:

 #include  // Need an exception safe locking class. struct MutexLocker { MutexLocker(pthread_mutex_t& m) :mutex(m) { if (pthread_mutex_lock(&mutex) != 0) {throw int(1); }} ~MutexLocker() { if (pthread_mutex_unlock(&mutex) != 0) {throw int(1); }} private: pthread_mutex_t& mutex; }; class Semaphore { public: Semaphore(int initCount = 0) : count(initCount) , waitCount(0) { if (pthread_mutex_init(&mutex, NULL) != 0) { throw int(1); } if (pthread_cond_init(&cond, NULL) != 0) { pthread_mutex_destroy(&mutex); throw int(2); } } void wait() { MutexLocker locker(mutex); while(count == 0) { ++waitCount; if (pthread_cond_wait(&cond, &mutex) != 0) { throw int(2); } // A call to pthread_cond_wait() unlocks the mutex and suspends the thread. // It does not busy wait the thread is suspended. // // When a condition variable receives apthread_cond_signal() a random thread // is un-suspended. But it is not released from the call to wait // until the mutex can be reacquired by the thread. // // Thus we get here only after the mutex has been locked. // // You need to use a while loop above because of this potential situation. // Thread A: Suspended waiting on condition variable. // Thread B: Working somewhere else. // Thread C: calls signal() below (incrementing count to 1) // This results in A being awakened but it can not exit pthread_cond_wait() // until it requires the mutex with a lock. While it tries to // do that thread B finishes what it was doing and calls wait() // Thread C has incremented the count to 1 so thread B does not // suspend but decrements the count to zero and exits. // Thread B now aquires the mutex but the count has been decremented to // zero so it must immediately re-suspend on the condition variable. // Note a thread will not be released from wait until // it receives a signal and the mustex lock can be re-established. --waitCount; } --count; } void signal() { // You could optimize this part with interlocked increment. MutexLocker locker(mutex); ++count; // This Comment based on using `interlocked increment` rather than mutex. // // As this part does not modify anything you don;t actually need the lock. // Potentially this will release more threads than you need (as you don't // have exclusivity on reading waitCount but that will not matter as the // wait() method does and any extra woken threads will be put back to sleep. // If there are any waiting threads let them out. if (waitCount > 0) { if (pthread_cond_signal(&cond) != 0) { throw int(2); } } } private: unsigned int count; unsigned int waitCount; pthread_mutex_t mutex; pthread_cond_t cond; }; 

在.NET中,BCL中存在一个实现: System.Threading.Semaphore 。

对于Windows上的本机代码,请查看CreateSemaphore函数 。 如果你的目标是Linux,那么你可以在这里找到维也纳科技大学的信号量实现(我之前已经使用过它并且有效)。

在C ++中,对于阻塞线程的方法,我建议你使用条件变量而不是信号量。 在C#中, 监视器可能更合适。

即使对于生产者 – 消费者问题的一个相当简单的情况,基于信号量的解决方案也很难做到:以错误的顺序执行信号量增量和减量可能会导致问题。 相反,基于条件变量的解决方案不会出现这样的问题:条件变量与锁(互斥锁)一起使用,并且自动施加正确的操作顺序; 所以在唤醒之后,一个线程已经获得了锁。

另见我的asnwer to 何时应该使用信号量? 我给出了另一个条件变量的例子,在我看来更适合于一个经常用信号量解决的问题。

为了解决另一个问题,我认为更高的错误使用责任和更高的解决方案复杂性(与替代方案相比)是某些线程包不提供信号量的原因。 对于TBB,我可以肯定地说。 C ++ 11中的线程支持(在Boost.Thread之后设计)也没有它; 看安东尼威廉斯的回答为什么。