std::atomic_int test1(0);
std::atomic_int test2(0);
+std::atomic_int ready(2);
+std::atomic_int which(0);
void f1()
{
- std::unique_lock<std::mutex> lk(mut);
- assert(test1 == 0);
- while (test1 == 0)
- cv.wait(lk);
- assert(test1 == 1);
- test1 = 2;
+ --ready;
+ std::unique_lock<std::mutex> lk(mut);
+ assert(test1 == 0);
+ while (test1 == 0)
+ cv.wait(lk);
+ which = 1;
+ assert(test1 == 1);
+ test1 = 2;
}
void f2()
{
- std::unique_lock<std::mutex> lk(mut);
- assert(test2 == 0);
- while (test2 == 0)
- cv.wait(lk);
- assert(test2 == 1);
- test2 = 2;
+ --ready;
+ std::unique_lock<std::mutex> lk(mut);
+ assert(test2 == 0);
+ while (test2 == 0)
+ cv.wait(lk);
+ which = 2;
+ assert(test2 == 1);
+ test2 = 2;
}
int main(int, char**)
{
- std::thread t1(f1);
- std::thread t2(f2);
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- {
- std::unique_lock<std::mutex>lk(mut);
- test1 = 1;
- test2 = 1;
- }
- cv.notify_one();
- {
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- std::unique_lock<std::mutex>lk(mut);
- }
- if (test1 == 2)
- {
- assert(test2 == 1);
- t1.join();
- test1 = 0;
- }
- else if (test2 == 2)
- {
- assert(test1 == 1);
- t2.join();
- test2 = 0;
- }
- else
- assert(false);
- cv.notify_one();
- {
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- std::unique_lock<std::mutex>lk(mut);
- }
- if (test1 == 2)
- {
- assert(test2 == 0);
- t1.join();
- test1 = 0;
- }
- else if (test2 == 2)
- {
- assert(test1 == 0);
- t2.join();
- test2 = 0;
- }
- else
- assert(false);
+ std::thread t1(f1);
+ std::thread t2(f2);
+ while (ready > 0)
+ std::this_thread::yield();
+ // In case the threads were preempted right after the atomic decrement but
+ // before cv.wait(), we yield one more time.
+ std::this_thread::yield();
+ {
+ std::unique_lock<std::mutex>lk(mut);
+ test1 = 1;
+ test2 = 1;
+ ready = 1;
+ }
+ cv.notify_one();
+ {
+ while (which == 0)
+ std::this_thread::yield();
+ std::unique_lock<std::mutex>lk(mut);
+ }
+ if (test1 == 2) {
+ assert(test2 == 1);
+ t1.join();
+ test1 = 0;
+ } else {
+ assert(test1 == 1);
+ assert(test2 == 2);
+ t2.join();
+ test2 = 0;
+ }
+ which = 0;
+ cv.notify_one();
+ {
+ while (which == 0)
+ std::this_thread::yield();
+ std::unique_lock<std::mutex>lk(mut);
+ }
+ if (test1 == 2) {
+ assert(test2 == 0);
+ t1.join();
+ test1 = 0;
+ } else {
+ assert(test1 == 0);
+ assert(test2 == 2);
+ t2.join();
+ test2 = 0;
+ }
return 0;
}