Search code examples
c++multithreadingc++11stdatomic

synchronizing 10 threads with atomic bool


I'm trying to use 10 threads and each one needs to print his number and the printing needs to be synchronized. I'm doing it as homework and I have to use atomic variables to do it (no locks).

Here what I tried so far:

#include <atomic>
#include <thread>
#include <iostream>
#include <vector>

using namespace std;
atomic<bool> turn = true;

void print(int i);

int main()
{
  vector<thread> threads;

  for (int i = 1; i <= 10; i++)
  {
    threads.push_back(thread(print, i));
  }

  for (int i = 0; i < 10; i++)
  {
    threads[i].join();
  }

  return 0;
}


void print(int i)
{
  bool f = true;
  for (int j = 0; j < 100; j++)
  {
    while((turn.compare_exchange_weak(f, false)) == false)
    { }
    cout << i << endl;
    turn = turn.exchange(true);
  }
}

output example:

24 

9143 
541 

2 
8

expected output:

2
4
9
1
4
3
1
5 
4
10
8

Solution

  • You have 2 bugs in your use of atomic.

    When compare_exchange_weak fails it stores the current value in the first parameter. If you want to keep trying the same value you need to set it back to the original value:

    while ((turn.compare_exchange_weak(f, false)) == false)
    {
      f = true;
    }
    

    The second issue is that exchange returns the currently stored value so:

    turn = turn.exchange(true);
    

    Sets the value of turn back to false, you need just:

    turn.exchange(true);
    

    Or even just:

    turn = true;
    

    Synchronisation isn't actually necessary in this case as std::cout will do the synchronisation for you, single output operations wont overlap so you can just change your print function to the following and it will just work:

    void print(int i)
    {
        for (int j = 0; j < 100; j++)
        {
            cout << std::to_string(i) + "\n";
        }
    }
    

    Atomics aren't the right approach to this problem, your code is incredibly slow. Mutexes would probably be quicker.