这是我第一次尝试编写多线程 C++ 代码,它似乎造成了数据竞争。这是完整的文件。它被编译为: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;
}
输出在每次运行时都以不可重现的方式加扰,例如:
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+ |
或
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+ |
有什么办法可以解决这个问题吗?我从中学到了很多关于 cout 对象的知识,但是一次只允许一个线程访问 cout 是规则吗,尤其是在使用 iomanip 时?
编辑:我的理解是: http://www.cplusplus.com/reference/iomanip/setw/ 以这种方式使用 iomanip 可能会导致数据争用。 所以问题是,不应该尝试这样做吗?是否应该创建每个要 cout 的线程,执行其业务,然后加入? (即根本没有线程)就是这样?如果是这样,那很好,并发的主要思想更多的是让一个程序打开多个并发的 fstream 对象,这样用户就不必等待,一个线程 cout 就可以了。我想问的是,这是标准方法吗?
最佳答案
你可以使用 std::mutex和一个 std::lock_guard :
#include <iomanip>
#include <iostream>
#include <mutex>
#include <thread>
const int SIZE = 5;
std::mutex iomutex;
void mult(int x, int y) {
// Complex, time-consuming calculations run multithreaded
auto res = x * y;
// lock stops other threads at this point
std::lock_guard<std::mutex> lock(iomutex);
// IO is singlethreaded
std::cout.width(3);
std::cout << std::right << res << "* ";
// lock leaves scope and is unlocked, next thread can start IO
}
void add(int x, int y) {
// Complex, time-consuming calculations run multithreaded
auto res = x + y;
// lock stops other threads at this point
std::lock_guard<std::mutex> lock(iomutex);
// IO is singlethreaded
std::cout.width(3);
std::cout << std::right << res << "+ ";
// lock leaves scope and is unlocked, next thread can start IO
}
int main() {
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;
}
在此示例中,多线程没有任何意义,但在更大的示例中,您只会保护输入/输出。计算并行运行。
关于c++ - 在多线程程序中使用 std::cout 和 <iomanip> 时如何避免数据竞争?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58044802/