在线程安全队列中使锁定范围更小

时间:2016-10-18 14:58:31

标签: multithreading c++11 mutex condition-variable

我有一个dll,它具有在高优先级线程中运行的高优先级功能。这个dll需要报告进度。基本上使用回调系统。问题是dll无法控制回调完成所需的时间。这意味着高优先级功能取决于回调的实现,这是不可接受的。

我们的想法是在中间有一个类来缓冲进度通知并调用回调。

我是C ++ 11的新手,它是线程功能并试图发现可能性。我有一个实现,但我有一个问题(至少有一个,我现在看到)。当线程在等待之后唤醒时,重新获取互斥锁并保持获取直到下一次等待。这意味着只要漫长的操作继续,就会获取锁定。添加进度将阻止此处。基本上很多代码都没有收获。我想把代码改成这个,但我不知道这是不是正确的实现。

        Progress progress = queue.front();
        queue.pop();
        lock.unlock();
        // Do lengthy operation with progress
        lock.lock();

我想我需要等待条件变量,但不应该连接到锁。我不知道如何做到这一点。通过虚拟锁并使用不同的锁来保护队列?如何在C ++ 11中解决这个问题?

头文件

#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <queue>

#include "Error.h"
#include "TypeDefinitions.h"


struct Progress
{
    StateDescription State;
    uint8 ProgressPercentage;
};

class ProgressIsolator
{
public:
    ProgressIsolator();
    virtual ~ProgressIsolator();

    void ReportProgress(const Progress& progress);
    void Finish();

private:
    std::atomic<bool> shutdown;
    std::condition_variable itemAvailable;
    std::mutex mutex;
    std::queue<Progress> queue;
    std::thread worker;

    void Work();
};

cpp文件

#include "ProgressIsolator.h"

ProgressIsolator::ProgressIsolator() :
    shutdown(false),
    itemAvailable(),
    worker([this]{ Work(); }),
    progressCallback(progressCallback),
    completedCallback(completedCallback)
{
    // TODO: only continue when worker thread is ready and listening?
}

ProgressIsolator::~ProgressIsolator()
{
    Finish();
    worker.join();
}

void ProgressIsolator::ReportProgress(const Progress& progress)
{
    std::unique_lock<std::mutex> lock(mutex);
    queue.push(progress);
    itemAvailable.notify_one();
}

void ProgressIsolator::Finish()
{
    shutdown = true;
    itemAvailable.notify_one();
}

void ProgressIsolator::Work()
{
    std::unique_lock<std::mutex> lock(mutex);

    while (!shutdown)
    {
        itemAvailable.wait(lock);
        while (!queue.empty())
        {
            Progress progress = queue.front();
            queue.pop();
            // Do lengthy operation with progress
        }
    }
}

1 个答案:

答案 0 :(得分:0)

void ProgressIsolator::Work()
{
    while (!shutdown)
    {
        Progress progress;
        {
            std::unique_lock<std::mutex> lock(mutex);
            itemAvailable.wait(lock, [this] { return !queue.empty(); });
            progress = queue.front();
            queue.pop();
        }
        // Do lengthy operation with progress
    }
}