Я пытаюсь понять, что происходит с мьютексом, когда он используется в условной переменной.
В следующем примере, взятом из cppreference
int main()
{
std::queue<int> produced_nums;
std::mutex m;
std::condition_variable cond_var;
bool done = false;
bool notified = false;
std::thread producer([&]() {
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::unique_lock<std::mutex> lock(m);
std::cout << "producing " << i << '\n';
produced_nums.push(i);
notified = true;
cond_var.notify_one();
}
done = true;
cond_var.notify_one();
});
std::thread consumer([&]() {
std::unique_lock<std::mutex> lock(m);
while (!done) {
while (!notified) { // loop to avoid spurious wakeups
cond_var.wait(lock);
}
while (!produced_nums.empty()) {
std::cout << "consuming " << produced_nums.front() << '\n';
produced_nums.pop();
}
notified = false;
}
});
producer.join();
consumer.join();
}
Поток производителя вызывает cond_var.notify_one (), прежде чем мьютекс разблокируется. Разблокируется ли мьютекс m при вызове notify или уведомление появляется только тогда, когда мьютекс разблокируется?
Уведомление не разблокирует мьютекс. Вы можете сказать (косвенно), потому что вы не передаете блокировку notify_one()
как вы делаете wait()
, который освобождает мьютекс, пока он ждет.
С другой стороны, уведомленные темы являются уведомил «немедленно». Но они не обязательно вернутся из wait()
немедленно. Прежде чем они смогут вернуться из wait()
сначала они должны повторно получить мьютекс, поэтому они будут блокироваться там до тех пор, пока уведомляющий поток не освободит его.
Замок получается в конструкторе и освобождается в деструкторе std::unique_lock
, Из этой информации вы можете сделать вывод, что производитель снимает блокировку после вызова notify_one()
завершается.
Из соображений производительности предлагаю разблокировать мьютекс, прежде чем уведомлять другие потоки.