printf调用被std :: thread弄乱了,但是std :: cout很好 [英] printf calls messed up with std::thread but std::cout are fine

查看:61
本文介绍了printf调用被std :: thread弄乱了,但是std :: cout很好的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

When printf (stdio.h) is used, "Start both threads\n" and "Enter a number\n" mixed together (something like "StEanterrt b a oth thnureaber\nads\n"), but this does not happen in std::cout (iostream). I suspect this has something to do with std::thread, but I am still new with multi-threading programming.

我真的不想使用iostream,因为它会使程序变得非常大!

I really don't want to use iostream because it makes the program super large!

我正在使用mingw32 g ++ 4.9.2,使用g++ -o foreback foreback.cpp -O2 -std=c++11进行编译. (虽然我的计算机是64位的,但是我发现mingw-w64生成的程序大约是mingw32的两倍,所以我没有使用它.)

I am using mingw32 g++ 4.9.2, compile with g++ -o foreback foreback.cpp -O2 -std=c++11. (Although my computer is 64-bits, but I find out that mingw-w64 produces program about twice the size by mingw32, so I didn't use it).

//#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]中指出:

std::cout provides no guarantees on interleaving either; it's not mentioned in C++03, and C++11's FDIS says the following in §27.4.1 [iostream.objects.overview]:

多个线程同时访问同步(第27.5.3.4节)标准iostream对象的格式化和未格式化输入(第27.7.2.1节)和输出(第27.7.3.1节)功能或标准C流,不应导致数据种族(§1.10). [注意:如果用户希望避免交织字符,则仍必须同步多个线程对这些对象和流的并发使用. —尾注]

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插入字符".通常可能是由于特定于编译器/运行时库的实现,或者由于尝试以使其自身与stdio.h 同步(关闭sync_with_stdio可能会导致它再次开始交错).但这不是语言保证;你只是幸运了.

That note at the end basically means "std::cout is allowed to interleave characters too". It's possible it isn't doing so due to the compiler/runtime library specific implementation in general, or due to the attempts to synchronize itself with stdio.h (turning off sync_with_stdio might cause it to begin interleaving again). But it's not a language guarantee; you're just lucking out.

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

If you want output to not interleave, you need to either perform all I/O from a single thread (have your workers take arguments and compute values, and the main thread is responsible for performing the I/O to output the computed values), or explicitly lock around all I/O functions that are used from different threads that target the same stream/FILE*. You could easily use stdio.h, you'd just need to have a std::mutex that you lock (e.g. with std::lock_guard) around your uses of stdio.h functions; as long as it's done consistently, you're guaranteed no interleaving.

这篇关于printf调用被std :: thread弄乱了,但是std :: cout很好的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆