educative.io

How is there a data race in example

Hi,

The discussion talks about “valSleeper should be protected using either a lock or an atomic”. How is there a data race in this example?


Course: https://www.educative.io/courses/concurrency-with-modern-cpp
Lesson: https://www.educative.io/courses/concurrency-with-modern-cpp/7AygKprPzGG

Hi @Aditya_Sharma,
A data race occurs in concurrent programming when two or more threads access a shared resource (in this case, the variable valSleeper) concurrently, and at least one of the accesses is a write operation. If these accesses are not properly synchronized, it can lead to unpredictable behavior due to the interleaving of operations.

In the provided example, the Sleeper class defines a callable object (functor) that modifies the shared variable i (a reference to valSleeper). This modification happens within the operator() function of the Sleeper class, which is invoked concurrently by the main thread and the spawned thread (t). Both threads access and modify valSleeper concurrently, potentially leading to a data race.

To fix the data race, the suggested solution is to protect the shared variable valSleeper using synchronization mechanisms such as locks or atomics. In the modified main function, the std::thread object t is joined instead of detached, ensuring that the main thread waits for the spawned thread to finish its execution before proceeding. This synchronization ensures that modifications to valSleeper are properly coordinated, eliminating the data race.

While joining the thread resolves the data race issue by ensuring sequential execution, it may introduce performance overhead due to thread synchronization and waiting. However, it ensures that the final value of valSleeper is consistent and deterministic, even though the execution may be slower.