Consider this case (which is the standard usage in cppreferences):
std::atomic<bool> condition(false);
thread 1:
lock
// check condition the last time before waiting
if (condition == true) { unlock; return; }
// to be clear, I expand "wait" here
{
// In my understanding
post task to waiting list
unlock
yield
lock
check condition
...
}
thread 2:
lock
condition=true
notify_one
unlock
I understand that thread 2 needs lock and unlock, so that notify_one won't be called after checking condition but before posting task to waiting list (in my understanding, notify_one does nothing if the task has not been posted to waiting list).
However, I think modifying condition (condition=true in the example) does not require owning the mutex, that is to say, I think this should also work:
thread 2:
condition=true
lock
notify_one
unlock
Because in my understanding, if notify_one is called before thread 1 locks, then the condition check before wait would return true, and thread 1 wouldn't wait at all. If notify_one is called after thread 1 unlocks, the task has already been posted to waiting list, so thread 1 can wake up and check condition, which has already been true.
However, cppreferences says even if the shared variable is atomic, it must be modified while owning the mutex. Is there something I miss?
Related:
Why do pthreads’ condition variable functions require a mutex?
Why does a condition variable need a lock (and therefore also a mutex)
But my question is more specific than them.
Update: I tried to test my idea of modifying condition without owning the mutex, and it works fine so far:
#include <iostream>
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
std::mutex mu;
std::atomic<bool> condition(false);
std::condition_variable cv;
void thread_1() {
std::unique_lock<std::mutex> lock(mu);
if (condition.load() == true)
return;
cv.wait(lock);
}
void thread_2() {
condition.store(true);
std::unique_lock<std::mutex> lock(mu);
cv.notify_one();
}
int main() {
for (size_t i = 0; i < 100000; ++i) {
std::thread t1(thread_1);
std::thread t2(thread_2);
t1.join();
t2.join();
}
return 0;
}
notify_onewithout owning the mutex also works. I'm just wondering whether it is possible to modify condition without owning the mutex. I have edited the question to make it more clear.notify_one. However, my ultimate goal is indeed avoiding locking andnotify_onefor producers if the consumer is not waiting, which is only possible if the producers can avoid owning the mutex when modifying the condition.