首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >条件变量和无锁容器

条件变量和无锁容器
EN

Stack Overflow用户
提问于 2013-06-10 18:25:44
回答 2查看 1.5K关注 0票数 3

条件变量使用互斥锁,.wait()函数解锁互斥锁,这样另一个线程就可以访问共享数据。当通知条件变量时,它会再次尝试锁定互斥锁以使用共享数据。

Anthony Williams中的以下concurrent_queue示例中使用了此模式

代码语言:javascript
复制
template<typename Data>
class concurrent_queue
{
private:
    boost::condition_variable the_condition_variable;
public:
    void wait_for_data()
    {
        boost::mutex::scoped_lock lock(the_mutex);
        while(the_queue.empty())
        {
            the_condition_variable.wait(lock);
        }
    }
    void push(Data const& data)
    {
        boost::mutex::scoped_lock lock(the_mutex);
        bool const was_empty=the_queue.empty();
        the_queue.push(data);
        if(was_empty)
        {
            the_condition_variable.notify_one();
        }
    }
};

由于代码使用std::queue,因此很明显,在访问队列时必须锁定互斥锁。但是假设使用来自PPL的Microsofts Concurrency::concurrent_queue而不是std::queue one。像empty、push和try_pop这样的成员函数是线程安全的。在这种情况下,我是否仍然需要锁定互斥锁,或者是否可以像这样使用条件变量,而不会创建任何可能的竞争条件。

我的代码(这似乎可以工作,但这在多线程中意味着什么?)看起来像这样。我有一个生产者推送项目到微软的concurrent_queue和一个后台线程,等待新的项目在这个队列中。

使用者/后台线程:

代码语言:javascript
复制
while(runFlag) //atomic
{
    while(the_queue.empty() && runFlag) //wait only when thread should still run
    {
        boost::mutex mtx; //local mutex thats locked afterwards. awkward.
        boost::mutex::scoped_lock lock(mtx);
        condition.wait(lock);
    }

    Data d;
    while(!the_queue.empty() && the_queue.try_pop(d))
    {
       //process data
    }
}

生产者/主线程:

代码语言:javascript
复制
const bool was_empty = the_queue.empty();
Data d; 
the_queue.push(d);
if(was_empty) cond_var.notify_one();

关闭过程:

代码语言:javascript
复制
bool expected_run_state = true;
if(runLoop.compare_exchange_strong(expected_run_state, false))
{
    //atomically set our loop flag to false and 
    //notify all clients of the queue to wake up and exit
    cond_var.notify_all();
}

如上所述,这段代码似乎可以工作,但这并不意味着它是正确的。特别是本地互斥锁,因为条件变量接口迫使我使用互斥锁,所以才使用它,这似乎是一个非常糟糕的想法。我想使用条件变量,因为添加到队列的数据项之间的时间很难预测,我必须像这样周期性地创建睡眠和唤醒:

代码语言:javascript
复制
if(the_queue.empty()) Sleep(short_amount_of_time);

有没有其他的,也许是操作系统(在我的例子中: Windows)特定的工具,可以让后台线程休眠,直到满足某个条件,而不需要定期唤醒和检查条件?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-06-10 18:45:10

例如,代码在不同的场景中是不正确的。如果在计算const bool was_empty = the_queue.empty();时队列只有一个元素,但是一个线程消费了该元素,而另一个线程试图消费并等待该条件,则在队列中插入该元素后,编写器不会通知该线程。

关键问题是,接口中的所有操作都是线程安全的这一事实并不一定意味着您使用该接口是安全的。如果您依赖于原子执行的多个操作,则需要在外部提供同步机制。

票数 1
EN

Stack Overflow用户

发布于 2013-06-10 19:31:46

有没有其他的,也许是操作系统(在我的例子中: Windows)特定的工具,可以让后台线程休眠,直到满足某个条件,而不需要定期唤醒和检查条件?

这正是Events的作用所在

但是,如果您只针对Windows platform (Vista+),那么您应该查看

Slim Reader/Writer (SRW) Locks

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17021696

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档