Windows中的进程间条件变量

时间:2011-08-01 08:15:08

标签: windows winapi windows-7 synchronization

我知道我可以使用条件变量来同步线程之间的工作,但是有任何类like this (condition variable)来同步进程之间的工作,提前感谢

5 个答案:

答案 0 :(得分:2)

您可以使用named semaphorenamed mutex。您还可以通过shared memory在进程之间共享内存。

答案 1 :(得分:1)

使用一对名为Semaphore的对象,一个用于发信号,一个用作锁。 Windows上的命名同步对象是自动进行处理的,它会为您处理该部分工作。

这样的一个类就可以了。

class InterprocessCondVar {
private: 
    HANDLE  mSem;        // Used to signal waiters
    HANDLE  mLock;       // Semaphore used as inter-process lock 
    int     mWaiters;    // # current waiters 

protected: 

public: 
    InterprocessCondVar(std::string name)
       : mWaiters(0), mLock(NULL), mSem(NULL)
    {
        // NOTE: You'll need a real "security attributes" pointer 
        //   for child processes to see the semaphore! 
        //  "CreateSemaphore" will do nothing but give you the handle if 
        // the semaphore already exists. 
        mSem = CreateSemaphore( NULL, 0, std::numeric_limits<LONG>::max(),  name.c_str()); 

        std::string lockName = name + "_Lock";
        mLock = CreateSemaphore( NULL, 0, 1, lockName.c_str());
        if(!mSem || !mLock) {
            throw std::runtime_exception("Semaphore create failed");
        }
    }
    virtual ~InterprocessCondVar() {
        CloseHandle( mSem);
        CloseHandle( mLock);
    }

    bool Signal();
    bool Broadcast();
    bool Wait(unsigned int waitTimeMs = INFINITE); 
}

真正的条件变量提供3个电话:
1)“信号()”:唤醒一个等待线程

bool InterprocessCondVar::Signal() {
    WaitForSingleObject( mLock, INFINITE);           // Lock
    mWaiters--;                                      // Lower wait count
    bool result  = ReleaseSemaphore( mSem, 1, NULL); // Signal 1 waiter 
    ReleaseSemaphore( mLock, 1, NULL);               // Unlock 
    return result;
}

2)“Broadcast()”:唤醒所有线程

 bool InterprocessCondVar::Broadcast() {
    WaitForSingleObject( mLock, INFINITE);                 // Lock 
    bool result = ReleaseSemaphore( mSem, nWaiters, NULL); // Signal all
    mWaiters = 0;                                          // All waiters clear;
    ReleaseSemaphore( mLock, 1, NULL);                     // Unlock 
    return result;       
}

3)“等待()”:等待信号

bool InterprocessCondVar::Wait(unsigned int waitTimeMs) {
    WaitForSingleObject( mLock, INFINITE);  // Lock
    mWaiters++;                             // Add to wait count
    ReleaseSemaphore( mLock, 1, NULL);      // Unlock 

    // This must be outside the lock
    return (WaitForSingleObject( mSem, waitTimeMs) == WAIT_OBJECT_0);
}

这应确保Broadcast()仅唤醒线程&amp;已经在等待的流程,而不是所有未来的流程。这也是一个非常重量级的对象。对于不需要跨进程存在的CondVar,我将创建一个具有相同API的不同类,并使用未命名的对象。

答案 2 :(得分:1)

对于我正在进行的项目,我需要一个条件变量和互斥实现,它可以处理死进程并且不会导致其他进程在这种情况下陷入死锁。我使用WIN32 api提供的本机命名互斥锁实现了互斥锁,因为它们可以通过返回WAIT_ABANDONED来指示死进程是否拥有锁。下一个问题是我还需要一个条件变量,我可以跨进程使用这些互斥锁。我从user3726672的建议开始,但很快发现有几个问题,其中计数器变量的状态和信号量的状态最终都是无效的。

在做了一些研究之后,我发现了微软研究院的一篇论文,它正好解释了这个场景:Implementing Condition Variables with Semaphores。它为每个线程使用单独的信号量来解决上述问题。

我的最终实现使用了一部分共享内存,我在其中存储了一个thread-iid的ringbuffer(等待线程的id)。然后,进程为每个尚未遇到的命名信号量/ thread-id创建自己的句柄并缓存它。信号/广播/等待功能非常直接,并遵循本文提出的解决方案的想法。如果等待操作失败或导致超时,请记住从ringbuffer中删除你的thread-id。

对于Win32实现,我建议您阅读以下文档: Semaphore ObjectsUsing Mutex Objects正如那些描述了您实施所需的功能。

替代方案:boost :: interprocess具有一些强大的互斥模拟支持,但它基于自旋锁并在我们的嵌入式系统上造成了非常高的CPU负载,这是我们调查自己的实现的最终原因。

@ user3726672:您是否可以更新您的帖子以指向此帖子或引用的论文?

最诚挚的问候, 迈克尔

<强>更新 我还看了一下linux / posix的实现。原来pthread已经提供了你需要的一切。只需将pthread_cond_t和pthread_mutex_t放在某个共享内存中,与其他进程共享,并使用PTHREAD_PROCESS_SHARED进行初始化。还要在互斥锁上设置PTHREAD_MUTEX_ROBUST。

答案 3 :(得分:0)

是。您可以使用(命名)Mutex。使用CreateMutex创建一个。然后等待它(使用WaitForSingleObject等函数),并在完成ReleaseMutex后释放它。

答案 4 :(得分:0)

作为参考,Boost.Interprocess(documentation for version 1.59)具有条件变量等等。但是,请注意,在撰写本文时,&#34; Win32 synchronization is too basic&#34;。