samedi 21 septembre 2019

How to avoid data races when using std::cout and

This is my first attempt at writing multithreaded C++ code and it seems to have created a data race. Here is the complete file. It was compiled as: g++ -pthread foo.cpp

#include <iostream>
#include <iomanip>
#include <thread>
const int SIZE = 5;

void mult(int x, int y) {
    std::cout.width(3); 
    std::cout << std::right << x * y << "* ";
}

void add(int x, int y) {
    std::cout.width(3); 
    std::cout << std::right << x + y << "+ ";
}

int main() {
    int a = 0;
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            std::thread first(mult, i, j);
            std::thread second(add, i, j);
            first.join();
            second.join();
            std::cout << " | ";
        }
        std::cout << "\n";
    }
     return 0;
}

The output is scrambled in a non-reproducible manner on each run, for example:

  0*   0+  |   0*   1+  |   2  0+ *  |   0*   3+  |   0*   4+  | 
  0*   1+  |   1*   2+  |   2*   3+  |   3*   4+  |   4*   5+  | 
  0*   2+  |   2*   3+  |   4*   4+  |   6*   5+  |   8*   6+  | 
  0*   3+  |   3  4* +  |   6*   5+  |   9*   6+  |  12*   7+  | 
  0*   4+  |   4*   5+  |   8*   6+  |  12*   7+  |  16*   8+  | 

or

  0*   0+  |   0*   1+  |   0*   2+  |   0*   3+  |   0*   4+  | 
  0*   1+  |   1*   2+  |   2*   3+  |   3*   4+  |   4*   5+  | 
  0*   2+  |   2*   3+  |   4*   4+  |   6*   5+  |   8*   6+  | 
  0*   3+  |   3*   4+  |   6*   5+  |   9* 6+  |  12*   7+  | 
  0*   4+  |   4*   5+  |   8*   6+  |  12*   7+  |  16*   8+  | 

Is there any way around this problem? I've learned a lot about cout objects from this, but is it the rule that only one thread should be allowed to access cout at a time, especially when using iomanip?

Aucun commentaire:

Enregistrer un commentaire