Printf调用与std::thread混淆,但std::cout没有问题

printf calls messed up with std::thread but std::cout are fine

本文关键字:std cout 有问题 thread 调用 Printf 混淆      更新时间:2023-10-16

当使用printf (stdio.h)时,"启动两个线程n"answers"输入一个数字n"混合在一起(类似于" steantert b a th thnureabernadsn"),但在std::cout (iostream)中不会发生这种情况。我怀疑这与std::thread有关,但我仍然是多线程编程的新手。

我真的不想使用iostream,因为它使程序超大!

我使用的是mingw32g++ 4.9.2,用g++ -o foreback foreback.cpp -O2 -std=c++11编译。(虽然我的电脑是64位的,但是我发现mingw-w64产生的程序大约是mingw32的两倍大,所以我没有使用它)

//#define IOS
#ifdef IOS
#include <iostream>
#endif
#include <stdio.h>
#include <thread>
#include <atomic>
#include <windows.h> // for Sleep()
std::atomic<int> atom(1);
void foreground() {
    int c = 1;
    while (c) {
#ifdef IOS
        std::cout << "Enter a number: ";
        std::cin >> c;
#else
        printf("Enter a number: ");
        scanf("%d", &c);
#endif
        atom.store(c, std::memory_order_relaxed);
    }
}
void background() {
    FILE *out = fopen("foreback.txt", "w");
    int c = 1;
    while (c) {
        fprintf(out, "%d", c);
        c = atom.load(std::memory_order_relaxed);
        Sleep(500);
    }
    fclose(out);
}
int main() {
    std::thread f(foreground), b(background);
#ifdef IOS
    std::cout << "Start both threads.n";
#else
    printf("Start both threads.n");
#endif
    f.join();
    b.join();
#ifdef IOS
    std::cout << "End of both threads.n";
#else
    printf("End of both threads.n");
#endif
    return 0;
}

std::cout也不保证交错;c++ 03中没有提到它,c++ 11的FDIS在§27.4.1 [iostream.objects.overview]中说了以下内容:

通过多个线程并发访问synchronized(§27.5.3.4)标准iostream对象的格式化和未格式化的输入(§27.7.2.1)和输出(§27.7.3.1)函数或标准C流不会导致数据竞争(§1.10)。[注:如果用户希望避免交叉字符,他们仍然必须同步多线程对这些对象和流的并发使用。]

最后的注释基本上意味着"std::cout也允许交错字符"。通常,由于编译器/运行时库特定的实现,或者由于试图与stdio.h同步(关闭sync_with_stdio可能会导致它再次开始交错),它可能不会这样做。但这并不是语言的保证;你真走运。

如果你想输出不交错,你需要从一个线程执行所有的I/O(让你的工人接受参数和计算值,主线程负责执行I/O来输出计算值),或者显式地锁定来自不同线程的所有I/O函数,目标是相同的流/FILE*。你可以很容易地使用stdio.h,你只需要有一个std::mutex,你锁定(例如与std::lock_guard)围绕你使用stdio.h函数;