这个线程池使用安全吗?

时间:2016-10-30 11:46:46

标签: c++ multithreading thread-safety locking threadpool

我将多个作业发布到线程池然后等待它完成。我想知道我是否在这里遗漏了一些东西,因为偶尔我的工作线程似乎会冻结。

我的主要线程是这样启动工人:

numJobsPosted = 0;
for(auto entry : list)
{
    numJobsPosted++;
    threadPool->post(std::bind(&Controller::workerFunc, this, entry));
}

std::unique_lock<std::mutex> lock(m_workerLock);
while(numJobsPosted > 0)
{
    m_workerCondition.wait(lock);
}

现在我的workerFunc看起来像这样:

void Controller::workerFunc(Entry entry)
{
    // do some work with entry

    // notify finished
    numJobsPosted--;
    if(numJobsPosted <= 0)
    {
        // does the look need to be around the numJobsPosted-- ?
        std::unique_lock<std::mutex> locker(m_workerLock);
        m_workerCondition.notify_one();
    }
}

上面的代码是安全的,还是我需要将锁定在减量运算符周围?

1 个答案:

答案 0 :(得分:2)

这可能取决于线程池内部逻辑或设置的详细信息(例如,如果您有一个线程,因此作业实际上是按顺序运行的),但假设numJobsPostedint或类似的内置类型,您的代码不是线程安全的 workerFunc中的这一行:

numJobsPosted--;
如果同时由几个工作执行,

很可能成为竞争条件的主题。

另外,我不确定你的线程池的post函数究竟做了什么,但是如果它立即将一个worker函数调度到一个线程并且一些worker函数可以立即返回,那么你还有另一种可能的竞争条件在主线程代码中的这一行之间:

numJobsPosted++;

workerFunc中的这一行:

numJobsPosted--;

为了使其安全,您可以例如使numJobsPosted成为原子,例如声明它(在C ++ 11中):

#include <atomic>
std::atomic_int numJobsPosted;

让你的workerFunc像这样:

void Controller::workerFunc(Entry entry)
{
    // do some work with entry

    // notify finished
    {
        std::unique_lock<std::mutex> locker(m_workerLock);
        numJobsPosted--;
        if(numJobsPosted <= 0)
        {
            m_workerCondition.notify_one();
        }
    }
}

可以解决第一场比赛条件,但不是第二场比赛。

(另外,我并不真正理解你在numJobsPosted上进行操作和测试的逻辑,但我认为这与你的问题不同)