0

I'm trying to understand C++ Multithreading and synchronize between many threads. Thus I created 2 threads the first one increments a value and the second one decrements it. what I can't understand why the resulted value after the execution is different than the first one, since I added and subtracted from the same value.

static unsigned int counter = 100; static bool alive = true; static Lock lock; std::mutex mutex; void add() { while (alive) { mutex.lock(); counter += 10; std::cout << "Counter Add = " << counter << std::endl; mutex.unlock(); } } void sub() { while (alive) { mutex.lock(); counter -= 10; std::cout << "Counter Sub = " << counter<< std::endl; mutex.unlock(); } } int main() { std::cout << "critical section value at the start " << counter << std::endl; std::thread tAdd(add); std::thread tSub(sub); Sleep(1000); alive = false; tAdd.join(); tSub.join(); std::cout << "critical section value at the end " << counter << std::endl; return 0; } 

Output

critical section value at the start 100

critical section value at the end 220

So what I need is how to keep my value as it's, I mean counter equal to 100 using those two threads.

12
  • 1
    It just means that the adder thread ran more times than the subtractor thread, depends on e.g. the scheduler etc. If you want the threads to run an equal number of times, you need to add extra logic for that. Commented Sep 1, 2015 at 13:25
  • 1
    The threads aren't guaranteed to have precisely equal time and given all they're doing is adding and subtracting, I suspect that the difference 120 is actually very small over a very large number of iterations. Commented Sep 1, 2015 at 13:27
  • 2
    If nothing else, the Add thread will have some "free" time while the Sub thread is created, Commented Sep 1, 2015 at 13:28
  • 2
    Easy: just don't start the threads. Then counter will always equal 100. Well really: it's just not clear what you want to achieve. Commented Sep 1, 2015 at 13:37
  • 1
    @MoezRebai You use threads precisely where you don't need this kind of synchronization. For example, if two tasks must be executed in strict alternation with no overlap, you don't use threads for those two tasks. Commented Sep 1, 2015 at 16:33

2 Answers 2

2

The problem is that both threads will get into an "infinite" loop for 1 second and they will get greedy with the mutex. Do a print in both functions and see which thread gets the lock more often.

Mutexes are used to synchronize access to resources so that threads will not read/write incomplete or corrupted data, not create a neat sequence.

If you want to keep that value at 100 at the end of execution you need to use a semaphore so that there will be an ordered sequence of access to the variable.

Sign up to request clarification or add additional context in comments.

1 Comment

I don't think there is a platform-independent implementation, but you could implement your own custom version easily. Just add 2 boolean variables for each thread, and when one thread finishes one loop it sets their variable to false and the other one to true. Access to the 2 variables must be synchronized by using mutexes.
1

I think, what you want is to signal to the subtracting thread, that you just have sucessfully added in the add thread, and vice versa. You'll have to additionally communicate the information, which thread is next. A naive solution:

bool shouldAdd = true; add() { while( alive ) { if( shouldAdd ) { // prefer lock guards over lock() and unlock() for exception safety std::lock_guard<std::mutex> lock{mutex}; counter += 10; std::cout << "Counter Add = " << counter << std::endl; shouldAdd = false; } } } sub() { while( alive ) { if( !shouldAdd ) { std::lock_guard<std::mutex> lock{mutex}; counter -= 10; std::cout << "Counter Sub = " << counter << std::endl; shouldAdd = true; } } } 

Now add() will busy wait for sub() to do its job before it will try and acquire the lock again.

To prevent busy waiting, you might chose a condition variable, instead of trying to only use a single mutex. You can wait() on the condition variable, before you add or subtract, and notify() the waiting thread afterwards.

2 Comments

Of course, in this case it would be better to have just one thread which does add and sub,
As @Moez Rebai wrote, he is trying to learn about the concepts of multithreaded programming. Therefore it is safe to assume, that this is not a real world example. Anyway it helps to understand locking and inter thread communication.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.