我实现了一个使用IO管道的应用程序。我有三个线程,一个读取数据(图像),一个对它们进行处理,另一个将处理后的图像写回磁盘。
我与读者线程和处理线程陷入僵局。线程都可以访问名为toDeblur的指针,该指针是指向下一个要处理的图像的指针。读取器线程读入图像,将其指针指向toDeblur,然后通知处理线程toDeblur包含要处理的图像。
读者线程的相关代码如下:
//Wait until it's okay to read again.
boost::unique_lock<boost::mutex> lock(*deblurLock);
while(toDeblur != NULL)
{
readCondition->wait(lock);
}
DeblurImage* read = readImage(is, fileName);
toDeblur = read;
cerr << "readImage notifying deblurCondition" << endl;
//Notify the processing thread(s) that an image is ready.
deblurCondition->notify_one();
处理线程:
//Wait for our condition variable.
boost::unique_lock<boost::mutex> lock(*deblurLock);
cerr << "processImage waiting for non-NULL image" << endl;
while(toDeblur == NULL)
{
cerr << "processImage waiting for deblurCondition variable" << endl;
deblurCondition->wait(lock);
}
readCondition->notify_one();
processImage(kernels, deblurP, toDeblur);
但是,我发现在运行此代码时,遇到通知时遇到死锁,处理线程检查toDeblur是否为NULL,发现它是否为,然后又回到睡眠状态,但是读者线程在将有效图像分配给toDeblur后通知它。
我错过了一些明显的东西吗?我能做些什么来确保处理线程能够看到Debllur的更新吗?
编辑:我应该补充一点,上面的片段是循环的一部分,因此锁定/等待在每轮读取/处理之前发生。
我从运行程序得到的输出如下:
processImage waiting for non-NULL image
processImage waiting for deblurCondition variable
readImage is starting a read
readImage notifying deblurCondition
processImage waiting for deblurCondition variable
所以processImage在收到通知后会被唤醒,但是看到toDeblur仍然是NULL并返回等待。
答案 0 :(得分:1)
为什么不用生产者 - 消费者队列排队'deblur'图像指针?您可以使用固定的* deblur池来控制它,在启动时创建并保存在池队列中。
如果处理有多个线程,则可能需要图像中的序列号以确保输出不会出现故障。
答案 1 :(得分:0)
你有两个条件变量共享一个锁/互斥锁,你最好使用一个独立的锁/互斥锁使每个条件变量伴随。顺便说一句,一个条件变量的典型用法是:
// wait
while(...){
boost::unique_lock<boost::mutex> lock(aMutex);
condVar->wait(lock);
}
// notify
{
boost::unique_lock<boost::mutex> lock(aMutex);
condVar->notify_one();
}
确保在调用wait / notify后很快释放锁定,否则,很可能导致死锁。
答案 2 :(得分:0)
我已经解决了这个问题。死锁的原因是toDeblur指针是按值而不是通过引用传递给线程的,这当然意味着当读者线程更新指针的值时,而不是它指向的对象,该更新没有反映在处理线程的指针副本中。