1

I am not able to print the output on the screen.I am using cppreference side (GCC 12.1 (c++20 )) compiler, Is there any deadlock situation in below example. Is there any online compiler i can use for trying this type of examples

#include <iostream>
#include <semaphore>
#include <thread>
#include <vector>

std::vector<int> myVec{};
std::counting_semaphore<1> prepareSignal(2);              // (1)

void prepareWork() 
{

    myVec.insert(myVec.end(), {0, 1, 0, 3});
    std::cout << "Sender: Data prepared."  << '\n';
    prepareSignal.release();                              // (2)
}

void completeWork() 
{

    std::cout << "Waiter: Waiting for data." << '\n';
    prepareSignal.acquire();                              // (3)
    myVec[2] = 2;
    std::cout << "Waiter: Complete the work." << '\n';
    for (auto i: myVec) std::cout << i << " ";
    std::cout << '\n';
}

int main() 
{
    std::cout << '\n';
    std::thread t1(prepareWork);
    std::thread t3(completeWork);
    std::thread t2(completeWork);
    t1.join();
    t3.join();
    t2.join();
    std::cout << '\n';
}
273K
  • 29,503
  • 10
  • 41
  • 64
Mangy
  • 119
  • 6
  • No deadlock, but undefined behavior. None of the threads are properly sequenced. Semaphores do not sequence. – Sam Varshavchik Sep 15 '22 at 17:47
  • If you have read the cppreference page, can you explain in your words how you expect the `counting_semaphore` to work here? Because the initialization is already incorrect, see preconditions here: https://en.cppreference.com/w/cpp/thread/counting_semaphore/counting_semaphore – user17732522 Sep 15 '22 at 17:48
  • Uh, why the template argument of `counting_semaphore` is smaller than the constructor argument? – HolyBlackCat Sep 15 '22 at 17:57

1 Answers1

1

There is no deadlock, but you have a race condition:

In completeWork, prepareSignal.acquire does not block the execution (Based on c++ documentation: "When the counter is zero, acquire() blocks until the counter is incremented"). In this case, the counter is set to 2, and there is no other acquire.

So the program may run completeWork earlier than prepareWork, which will execute myVec[2] = 2;. This causes undefined behavior since your vector is empty.

You can test such errors using Address Sanitizer.

See a live example here that highlights this issue by adding a 1 second sleep delay to prepareWork:

https://godbolt.org/z/YYsfq84bd

The address sanitizer output tells you exactly where the error is!

Ari
  • 7,251
  • 11
  • 40
  • 70
  • 1
    Also, thread sanitizer will give you more clear information on the data race and without needing to figure out where to test a delay: https://godbolt.org/z/zTqjnr6zE – user17732522 Sep 15 '22 at 18:05