c++ 11 线程在 Linux 和 Windows 上的不同行为

san*_*jay 1 c++ linux windows multithreading c++11

#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;
}
Run Code Online (Sandbox Code Playgroud)

我在 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
Run Code Online (Sandbox Code Playgroud)

但在使用 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
Run Code Online (Sandbox Code Playgroud)

在 Windows 上,两个线程一一打印,但在 Linux 上,行为不同。在 Linux 上使用互斥体不会同步。Linux下如何同步?

kfs*_*one 5

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

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

事实上,您在 Visual Studio 中看到类似的情况纯粹是巧合,并且不能保证,而您在 Linux 下看到的其他情况更可能是由于 IO 执行方式的差异而不是线程操作方式的差异。

我猜测你实际上想在这里做什么,但我怀疑你想要一个condition_variablenotify_one. 但是,您也不应该假设它会循环。

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

- - 编辑 - -

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