条件变量和lockfree容器

时间:2013-06-10 10:25:44

标签: c++ multithreading condition-variable

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

此模式用于Anthony Williams中的以下concurrent_queue示例:

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。会员功能如空, push和try_pop是线程安全的。我是否还需要锁定互斥锁 这种情况或者条件变量可以像这样使用,没有 创造任何可能的竞争条件。

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

消费者/后台主题:

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
    }
}

生产者/主线程:

const bool was_empty = the_queue.empty();
Data d; 
the_queue.push(d);
if(was_empty) cond_var.notify_one();

关机程序:

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();
}

如上所述,此代码似乎有效,但这并不一定意味着它是正确的。特别是仅因为条件变量接口强制我使用互斥锁而使用的本地互斥锁,这似乎是一个非常糟糕的主意。我想使用条件变量,因为添加到队列的数据项之间的时间难以预测,我必须创建睡眠并定期唤醒,如下所示:

if(the_queue.empty()) Sleep(short_amount_of_time);

是否还有其他操作系统(在我的情况下为Windows)特定工具,使后台线程处于睡眠状态,直到满足某些条件而无需定期唤醒并检查条件?

2 个答案:

答案 0 :(得分:1)

例如,在不同的场景中,代码不正确。如果在评估const bool was_empty = the_queue.empty();时队列具有单个元素,但是线程使用该元素并且另一个线程尝试使用并等待该条件,则在将该元素插入队列后,编写器将不会通知该线程。

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

答案 1 :(得分:1)

  

还有其他可能的OS(在我的情况下:Windows)特定工具,   使后台线程休眠直到满足某些条件   没有经常醒来并检查状况?

这正是Events的用途
但如果你只针对Windows平台(Vista +),你应该检查出来 Slim Reader/Writer (SRW) Locks