Не создавайте код таким образом, чтобы мьютекс удерживался все время или большую часть времени. Вот что вызывает у вас проблемы с честностью.
Звучит так, как будто вам нужна блокировка, которая дает приоритет одному потоку, так что, если приоритетный поток ожидает блокировки, неприоритетный поток останавливается. Ваш поток, выполняющий работу, должен использовать функцию неприоритетной блокировки, чтобы все ожидающие читатели остановили ее.
class prio_lock
{
private:
std::mutex m;
std::condition_variable cv;
int locked = 0;
int waiting_priority = 0;
public:
void lock(bool priority)
{
std::unique_lock<std::mutex> lk(m);
// wait for all prior priority locks
while (waiting_priority > 0)
cv.wait(lk);
if (priority)
++waiting_priority;
// wait for lock to be unlocked
while (locked != 0)
cv.wait(lk);
if (priority)
--waiting_priority;
// take the lock
locked = 1;
}
void unlock()
{
std::unique_lock<std::mutex> lk(m);
locked = 0;
cv.notify_all();
}
};
Обратите внимание, что даже если неприоритетный поток удерживает блокировку, приоритетный поток должен будет подождать, пока текущий держатель блокировки не снимет блокировку, прежде чем сможет продвинуться вперед. Это следствие вашего дизайна, который, я сильно подозреваю, не очень хорош. Потоки не должны удерживать блокировки, которые могут понадобиться другим потокам, в то время как они выполняют большую часть реальной работы, и все, что требуется в вашем проекте, требует переосмысления.
Я не знаю вашего полного внешнего дизайна, но если поток чтения должен иметь доступ только к статусу задания, похоже, что поток записи должен быть в состоянии выполнять большую часть своей реальной работы без доступа к статусу задания и должен удерживать блокировка только тогда, когда он меняет этот статус, а не пока он выполняет реальную работу.