c++ - printf 调用搞砸了 std::thread 但 std::cout 很好

标签 c++ multithreading c++11

当使用 printf (stdio.h) 时,“启动两个线程\n”和“输入数字\n”混合在一起(类似“StEanterrt b a oth thnureaber\nads\n”),但这不会发生在 std::cout (iostream) 中。我怀疑这与 std::thread 有关,但我对多线程编程还是个新手。

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

我正在使用 mingw32 g++ 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] 中说了以下内容:

Concurrent access to a synchronized (§27.5.3.4) standard iostream object’s formatted and unformatted input (§27.7.2.1) and output (§27.7.3.1) functions or a standard C stream by multiple threads shall not result in a data race (§1.10). [ Note: Users must still synchronize concurrent use of these objects and streams by multiple threads if they wish to avoid interleaved characters. — end note ]

末尾的注释基本上意味着“std::cout 也允许交错字符”。由于编译器/运行时库的特定实现,或者由于尝试 to synchronize itself with stdio.h,它可能没有这样做(关闭 sync_with_stdio 可能会导致它再次开始交错)。但这不是语言保证;你只是走运。

如果您希望输出不交错,您需要从单个线程执行所有 I/O(让您的工作人员获取参数和计算值,主线程负责执行 I/O 以输出计算的值值),或显式锁定从针对相同流/FILE* 的不同线程使用的所有 I/O 函数。您可以轻松地使用 stdio.h,您只需要有一个您锁定的 std::mutex(例如使用 std::lock_guard) 围绕您对 stdio.h 函数的使用;只要始终如一地完成,就可以保证不会出现交错。

关于c++ - printf 调用搞砸了 std::thread 但 std::cout 很好,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39092042/

相关文章:

C++11 快速 constexpr 整数幂

c++ - 嵌套类的替代方案

c++ - .tpp 文件中的 doxygen 和模板问题

c++ - 如何更改使用 STL 打印的精度?

c# - 除了使用线程之外,监视 C# 中的控件

c++ - 在 map 中插入 std::string 和指向对象的共享指针

c++ - 为什么我不能在 vector 迭代器中直接访问?

c# - 顶级任务导致错误 "The current SynchronizationContext may not be used as a TaskScheduler."

java vector 和线程安全

c++ - 观察者模式,智能指针和单例类