在我的项目中,我有多个线程将数据馈送到工作池。工作线程使用条件变量等待新数据。这在几个小时甚至几天内都可以正常工作,但是有时工人会永远std::condition_variable::wait_for()
挡住它。没有超时,也没有通知将其唤醒。我验证了工作线程仍然存在,它从未离开过wait_for()
。
工人的工作通常需要4到6毫秒。 pushWork()
平均每5毫秒添加一次新作业。这些新作业不是定期创建的,而是10-20个作业的爆发。在下面的示例代码中,我使用一个带有睡眠的假人来代替复杂的实际工作。
为什么这种零星的封锁会永远发生?
我的代码的简化版本,简化为重要部分:
#include <chrono>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <vector>
#include <iostream>
#include <cstdlib>
#include <atomic>
class TestWorker
{
public:
enum JobState
{
free = 0,
processing
};
TestWorker() : workerThread(&TestWorker::doWork, this)
{
}
~TestWorker()
{
stopWorker = true;
if (workerThread.joinable())
{
workerTrigger.notify_one();
workerThread.join();
}
}
void pushWork(const int data)
{
while (JobState::free != state)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
std::lock_guard<std::mutex> lock(workerMutex);
while (JobState::free != state)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
// Set dummy data for job ...
dummyData = data;
state = JobState::processing;
workerTrigger.notify_one();
}
void doWork()
{
std::unique_lock<std::mutex> triggerLock(workerMutex);
while (!stopWorker)
{
if (JobState::processing == state)
{
// Do something for 4-6ms with dummy job data
++dummyData;
std::this_thread::sleep_for(std::chrono::milliseconds(5)); // Dummy sleep instead of real job
state = JobState::free;
}
else
{
if (!workerTrigger.wait_for(triggerLock,
std::chrono::milliseconds(500),
[this]
{ return (stopWorker || (JobState::processing == state)); }))
{
if (!stopWorker)
{
std::cout << "TIMEOUT" << std::endl;
}
else
{
std::cout << "EXIT" << std::endl;
}
}
}
}
}
std::mutex workerMutex;
std::condition_variable workerTrigger;
bool stopWorker = false;
std::thread workerThread;
std::atomic<JobState> state = { JobState::free };
// Dummy data for job ...
int dummyData = 0;
};
int main()
{
std::cout << "START" << std::endl;
std::vector<TestWorker> testWorkers(10);
for (int i = 1; i <= 1000; ++i)
{
if (0 == i % 10)
{
std::cout << "Loop #" << i << std::endl;
}
for (auto it = testWorkers.begin(); it != testWorkers.end(); ++it)
{
it->pushWork(i);
}
}
std::cout << "END" << std::endl;
return 0;
}
编译与:g ++ workerTriggerTest.cc -o workerTriggerTest -pthread -std = c ++ 11
gcc版本4.8.5 20150623(红帽4.8.5-36)
CentOS Linux版本7.6.1810