Я реализую приложение, которое использует протокол ввода-вывода. У меня есть три потока, одно чтение в данных (изображения), одно из них обрабатывает их и одно записывает обработанные образы обратно на диск.
Я столкнулся с тупиком с нитью читателя и потоком обработки. В потоках есть доступ к указателю, называемому toDeblur, который является указателем на последующее обработку изображения. Читательский поток читается на изображении, присваивает его указатель toDeblur, а затем уведомляет поток обработки, что toDeblur содержит изображение для обработки.
Соответствующий код для потока читателя выглядит следующим образом:
//Wait until it 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.
Я пропустил что-то очевидное? Есть ли что-то, что я могу сделать, чтобы убедиться, что обновление toDeblur наблюдается в потоке обработки?
EDIT: Я должен добавить, что приведенные выше фрагменты являются частью циклов, поэтому блокировки/ожидания происходят до каждого раунда чтения/обработки.
Результат, который я получаю от запуска программы, выглядит следующим образом:
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 и возвращается к ожиданию.
Я решил проблему. Причина тупика заключается в том, что указатель toDeblur передавался потокам по значению, а не по ссылке, что, разумеется, означало, что когда поток читателя обновлял значение указателя, в отличие от указанного на нем объекта, это обновление не было отражено в копии указателя, который был обработан.
Почему бы не поставить очереди указателей изображений "deblur" с очередями производителей-потребителей? Возможно, вы можете контролировать поток с помощью фиксированного пула * deblur, созданного при запуске и удерживаемого в очереди пула.
Если обработка имеет более одного потока, вам может понадобиться номер последовательности в изображениях, чтобы гарантировать, что результат не выходит из строя.
У вас есть две условные переменные, разделяющие один замок/мьютекс, вам лучше сделать каждый условный переменный компаньон с независимой блокировкой/мьютексом. BTW, типичное использование одной условной переменной:
// 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, в противном случае высокая вероятность приведет к мертвой блокировке.
volatile
чтобы компилятор не оптимизировал ее.