在多线程应用程序中等待变量的最佳方法是什么?

时间:2010-01-13 20:57:01

标签: c++ c windows winapi resources

我想为多线程程序做类似的事情:

// wait for variable to become true but don't hog resources  
// then re-sync queues  

something like this是一个很好的解决方案吗?

while (!ready) {
    Thread.Sleep(250); // pause for 1/4 second;
};

8 个答案:

答案 0 :(得分:15)

不,这不是一个好的解决方案。首先,它可能会睡得太久。其次,线程很容易进入锁定阶段。以下是关于正确同步技术的MSDN文章的几个链接:

答案 1 :(得分:5)

以下是使用boost执行此操作的方法:

boost::condition_variable condvar;
boost::mutex mutex;
bool finished1 = false;
bool finished2 = false;

void longComputation1()
{
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished1 = false;
    }
    // Perform long computation
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished1 = true;
    }
    condvar.notify_one();
}

void longComputation2()
{
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished2 = false;
    }
    // Perform long computation
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished2 = true;
    }
    condvar.notify_one();
}

void somefunction()
{
    // Wait for long computations to finish without "spinning"
    boost::lock_guard<boost::mutex> lock(mutex);
    while(!finished1 && !finished2)
    {
        condvar.wait(lock);
    }

    // Computations are finished
}

为了简洁起见,我没有包含线程产生代码。

boost::lock_guard使用RAII惯用法在锁定对象超出范围时自动解锁互斥锁。对于在异常情况下防止死锁非常有用。

我发现条件变量比Microsoft的Event对象更不容易出错。如果你使用boost.Thread,你将获得跨平台可维护性的额外好处。

答案 2 :(得分:4)

尝试使用Event(内核对象)而不是简单变量,并通过以下方式替换循环:

WaitForSingleObject(hEventHandle, INFINITE);

答案 3 :(得分:1)

上面的代码可以使用,在某些情况下可能也适用。

您还可以查看关键部分或信号量 - 这将使您的应用程序阻塞并等待资源可用,

执行工作的线程抓取互斥锁,做了一些工作,同时,main方法也尝试抓取相同的互斥锁,但不能。当工作线程退出时,它们会释放互斥锁,主线程可以通过关键部分并继续。

答案 4 :(得分:0)

首先,你需要声明你的'ready'变量至少是'volatile',否则这可能会产生令人讨厌的副作用。其次,如果可能需要的持续时间确实非常长,那么,只要几分钟就可以睡觉 长期重新评估病情。

使用WinAPI的事件函数(CreateEvent, SetEvent(), WaitForSingleEvent())是最好的方法。当然它引入了一些开销,但通常很好。

如果您想坚持使用您的解决方案,在您再次入睡之前循环并重新检查该条件几次可以在某些情况下提高性能。

答案 5 :(得分:0)

原始的Win32 API有EVENT用于执行此操作,这是一个用法示例:

http://msdn.microsoft.com/en-us/library/ms686915(VS.85).aspx

但是,该API是面向C的,特别适用于Windows。如果编写C ++程序,您可以考虑使用boost :: threads这样的代码使代码更加独立于平台,它在Conditions中具有类似物。

我发现一个警告是Windows可以WaitForMultipleObjects,因此一次等待几个事件(和其他句柄类)。 boost没有平行的AFAIK。

答案 6 :(得分:0)

除了已经提供的好答案之外 - 假设您想要检测到的事件的随机分布,您将浪费一半的睡眠时间。 125ms是计算机时代的永恒。

Win32上的WaitForSingleObject事件句柄允许您立即伪检测所需的信号(取决于进程中的其他线程正在做什么),而不进行冗余检查(在信号之前必须执行多少个不必要的循环)到达?),提供设置线程一旦完成其工作就调用SetEvent。然后,bool是多余的,这应该是应该的。

答案 7 :(得分:-2)

当然这是C#,但我发现这本书对于进行多线程开发非常有帮助。

http://www.albahari.com/threading/

部分信息并非针对特定语言。