多线程 - 线程是否在同一时间开始运行?

时间:2017-11-22 18:31:08

标签: c++ multithreading

尝试理解多线程。如果我理解正确,线程不会在相同的时间启动,它们只是在写入的序列中一个接一个地并行运行。我们来举个例子

#include <string>
#include <iostream>
#include <thread>

using namespace std;

void task(string msg, int index)
{
    cout << "Thread " << index << " says: " << msg << endl;    
}

int main()
{
    cout << "Main thread begins" << endl;

    thread t1(task, "Hello", 1);
    thread t2(task, "Hello", 2);
    thread t3(task, "Hello", 3);
    thread t4(task, "Hello", 4);

    t1.join();
    t2.join();
    t3.join();
    t4.join();

    cout << "Back in main thread" << endl;

    return 0;
}

由于程序逐行执行,因此线程t1将首先开始,t2秒,t3第三和t4第四。一旦启动,它们将并行运行(与主线程一起)。上面的程序将显示不连贯的字符串,因为这是一个过于简单和快速的操作,每个线程竞相写入控制台。

如果我们给每个线程一些时间,那么输出将是连贯的。例如

#include <string>
#include <iostream>
#include <thread>

using namespace std;
using namespace std::this_thread;
using namespace std::chrono;

void task(string msg, int index)
{
    cout << "Thread " << index << " says: " << msg << endl;    
}

int main()
{
    cout << "Main thread begins" << endl;

    thread t1(task, "Hello", 1);
    sleep_for(seconds(3));
    thread t2(task, "Hello", 2);
    sleep_for(seconds(3));
    thread t3(task, "Hello", 3);
    sleep_for(seconds(3));
    thread t4(task, "Hello", 4);
    sleep_for(seconds(3));

    t1.join();
    t2.join();
    t3.join();
    t4.join();

    cout << "Back in main thread" << endl;

    return 0;
}

没有在任何地方明确说明线程的开始时间。这种理解是否正确?

1 个答案:

答案 0 :(得分:4)

计算线程何时启动或不通常是编程错误。是的,从技术上讲,一旦创建它就会启动一个线程。但这并不意味着它立即开始运行。操作系统调度程序可以在那里执行任何操作。

你可能意识到,你试图哄骗调度员做你想睡觉的事情并不能保证工作。

如果你需要线程来相互执行它们的执行,你需要做一些明确的事情来实现这一点。你的睡眠不算数,它只是祈祷,希望事情以你想要的方式出现。

::std::mutex这样的同步原语很受欢迎。我还在管道上使用了通信,尽管这种通信更常用于在进程之间进行同步。

例如,在Linux中,创建::std::thread会导致调用the clone system call。这个呼叫与通常的说法直接相反(两个进入,但只有一个可以离开)而不是一个进入和两个离开。一个线程进行系统调用,它从两次返回,每个线程一次。它首先返回的线程完全是任意的。如果你有两个核心,那么这个问题可能没有明智的答案。一旦从。返回系统调用,线程就会执行。

因此,如果要在一个线程中执行的一系列指令中创建多个线程,则描述这些新线程的内核数据结构将按程序中出现的执行顺序创建。但这并不意味着他们的任何指令都会运行。可能是创建它们全部四个的指令以连续不间断的顺序运行,然后内核决定暂停原始线程并执行第四个,但只有5个CPU指令值,然后是第1个,然后是3。可能是内核立即调度您在单独核心上创建的第一个线程,因此它的指令在创建下一个线程的内核数据结构的同时执行。

这里保证执行顺序的所有内容是原始线程将发出四个连续请求来创建描述四个新执行线程的4个新内核数据结构。这些结构将按顺序创建,但它们的创建顺序绝对不会与执行任何指令的顺序无关。