代码之家  ›  专栏  ›  技术社区  ›  ontherocks

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

  •  2
  • ontherocks  · 技术社区  · 7 年前

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

    #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 回复  |  直到 7 年前
        1
  •  4
  •   Omnifarious    7 年前

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

    正如您可能已经意识到的那样,您试图诱使调度程序在睡眠中做您想做的事情,但这甚至不能保证工作。

    如果需要线程彼此同步执行,则需要显式执行。你的睡眠并不重要,它只是一个祈祷,希望事情按你想要的方式发展。

    同步原语,如 ::std::mutex 都很受欢迎。我还使用了管道上的通信,不过这更常用于进程之间的同步。

    例如,在Linux中,创建 ::std::thread 导致调用 the clone system call . 这个呼叫与通常的说法(两个进入,但只有一个可以离开)相反,一个进入,两个离开。一个线程进行系统调用,然后返回两次,每个线程返回一次。它首先返回哪个线程是完全任意的。如果你有两个核心,这个问题可能没有合理的答案。从返回系统调用后,线程立即执行。

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