c++ 11个线程在linux和windows上的不同行为

Posted

技术标签:

【中文标题】c++ 11个线程在linux和windows上的不同行为【英文标题】:c++ 11 Threads different behaviour on linux and windows 【发布时间】:2015-05-25 09:07:59 【问题描述】:
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mx;
void some_function()

    while(1)
    
        std::lock_guard<std::mutex> mx_guard(mx);
        std::cout << "some_function()\n";
    


void some_other_function()

    while(1)
    
        std::lock_guard<std::mutex> mx_guard(mx);
        std::cout << "some_other_function\n";
    


int main()

    std::thread t1(some_function);
    std::thread t2 = std::move(t1); //t2 will be joined

    t1 = std::thread(some_other_function);

    if(t2.joinable())
    
        std::cout << "t2 is joinable()\n";
        t2.join(); //calling join for t1
    
    if(t1.joinable())
    
        std::cout << "t1 is joinable()\n";
        t1.join();
    
    return 0;

我在 windows 和 linux 上对该程序有不同的输出。在使用 Visual Studio 13 编译器的 Windows 上,我得到以下输出。

some_function()
some_other_function
some_function()
some_other_function
some_function()
some_other_function
some_function()
some_other_function
some_function()
some_other_function
some_function()
some_other_function

但是在使用 gcc 的 linux 上输出是不同的

some_function()
some_function()
some_function()
some_function()
some_function()
some_function()
some_function()
some_other_function
some_other_function
some_other_function
some_other_function
some_other_function
some_other_function
some_other_function

在 windows 上,两个线程一个接一个地打印,但在 linux 上,它的行为不一样。在 linux 上使用互斥锁不同步。如何在linux上同步?

【问题讨论】:

您的系统有多少个 CPU?不保证线程之间的执行顺序。 “在 linux 上使用互斥锁不同步” - 您无法从该输出中得出结论。完全没有。 究竟打算做什么?如果您提供的只是样板文件,我们将无法帮助您。 std::cout &lt;&lt; "some_function()\n"; 您在输出后缺少cout.flush(),这可能很好地解释了不同的行为。 你想同步什么?目前,您正在同步对 std::cout 的访问,仅此而已。您的互斥锁只是保证您不会得到如下输出:“some_funsome_other_function\nction()\n” 【参考方案1】:

mutex 只是一个锁,用于防止对共享资源的并发访问,在本例中为 std::cout。在这两种情况下,一次只有一个线程写入std::cout。虽然在某些情况下解锁互斥锁可能会导致唤醒另一个任务,但除非您自己负责操作系统/调度程序代码,否则您不应该期望或依赖它。

互斥锁限制了对 std::cout 的访问:如果您在没有锁保护的情况下运行相同的代码,您可能会在一个操作系统或另一个操作系统上看到乱码/混合输出。

您在 Visual Studio 中看到类似内容的事实纯属巧合,不能保证,而且您在 Linux 下看到其他内容的事实更有可能是 IO 执行方式的差异而不是线程执行方式的差异操作。

我在推测您在这里实际尝试做什么,但我怀疑您想要condition_variable 和notify_one。但是,您再次不应假设它会循环。

另外,joinable() 测试线程是否正在运行,join() 等待它们停止,但由于您的线程处于永久循环中,对join() 的第一次调用将永远挂起。

--- 编辑 ---

当我使用 /O2 在 Visual Studio 2015 下运行您的代码时,我得到的输出与您在 Linux 上报告的结果相同。

【讨论】:

如果我们在两个或多个线程中有无限循环,那么如何加入它们?或者我们应该使用一些标志并基于一些条件变量我们应该继续? 好吧,join 的意思是“等待退出”,如果你将while(1) 更改为for(size_t i = 0; i &lt; 10000; ++i),它们最终会结束,join() 会成功。 C++ 标准没有提供显式取消线程的方法。您可以使用std::shared_future&lt;void&gt; (en.cppreference.com/w/cpp/thread/shared_future) 作为通知您希望它们停止的线程的一种方式。见pastebin.com/uHVWSwyN

以上是关于c++ 11个线程在linux和windows上的不同行为的主要内容,如果未能解决你的问题,请参考以下文章

C++:Linux上的pthread状态监控

C++ u8 文字 - Windows 上的意外编码

进程和线程

Windows 与 Linux 上的 gSOAP C++ 代码

将程序 (.exe) 作为线程执行 - Window C++

MacOS 上的 gcc:奇怪的线程错误