std::thread join() function of multithreading

Keywords: C++

C++11 introduces the function std::thread join(), which is used to wait for a thread to complete its task. Let's take a step-by-step look at this function.

In a simple program, only one thread is required, that is, the main thread:

int main()
{
    cout << "The main thread starts running\n";
}

Now suppose I have to do a time-consuming job, download a video from a server and process it, then my code will become:

int main()
{
    cout << "The main thread starts running\n";
    download();  // Download Video locally
    process();  // Local processing
}

If I need two video materials to be processed locally together, I need to download them separately, and then process them together after all downloads are completed:

int main()
{
    cout << "The main thread starts running\n";
    download1();  // Download Video 1
    download2();  // Download Video 2
    process();  // Deal with it together
}

But this has a disadvantage: it wastes time, that is, one download is completed and the other can start downloading. It is completely serial processing.

If only two videos can be downloaded at the same time, then the thread will come in handy:

void download1()
{
    cout << "Start downloading the first video..." << endl;
    for (int i = 0; i < 100; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
        cout << "Download progress:" << i << endl;
    }
    cout << "The first video download is complete..." << endl;
}

void download2()
{
    cout << "Start downloading the second video..." << endl;
    for (int i = 0; i < 100; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(30));
        cout << "Download progress:" << i << endl;
    }
    cout << "The second video download is complete..." << endl;
}

int main()
{
    cout << "The main thread starts running\n";
    std::thread d2(download2);
    download1();

    process();
}

        The main thread calls d2 to download the second video and downloads the first video by itself, which reduces its workload and shortens the time. A closer look at the sleep in download2() shows that video 2 must be downloaded first when two videos with the same length of time are downloaded at the same time. In this way, video 2 is ready when the main thread finishes downloading video 1, It can be processed together later. But what if the download time of Video 2 is longer than that of video 1? Once the video has been downloaded, d2 has not finished its work, and there is no video 2 locally. There will be problems in the next processing, or it can not be processed directly. After d2 has finished its work, the main thread can process two videos.

In this scenario, std::thread is used   Join() function. Explanation of join() function:

The function returns when the thread execution has completed.
This synchronizes the moment this function returns with the completion of all the operations in the thread: 
This blocks the execution of the thread that calls this function until the function called on construction returns (if it hasn't yet).

There are two key points:

  • Who called this function? For the thread object that calls this function, you must wait until the method of this thread object (the method passed in during construction) is executed (or understood as the work of this thread is finished!), and the join() function can be returned.
  • In what thread environment is this function called? As mentioned above, you can't return until the thread method is executed, which must block the calling thread. That is, if a thread object calls this function in a thread environment, the thread environment will be blocked until the method passed in by the thread object during construction is executed, In addition, if the thread object has finished its own work before calling the join () function (the method passed in during construction is completed), the function will not block the thread environment, and the thread environment will execute normally. It can be understood that if the d2 thread object with slow execution speed calls the join() function in the main thread environment, the thread environment will be blocked. The main thread can not continue to execute until the method passed in by the d2 thread object during construction is completed, that is, the process() operation is completed.
void download1()
{
    cout << "Start downloading the first video..." << endl;
    for (int i = 0; i < 100; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
        cout << "First video download progress:" << i << endl;
    }
    cout << "The first video download is complete..." << endl;
}

void download2()
{
    cout << "Start downloading the second video..." << endl;
    for (int i = 0; i < 100; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(80));
        cout << "Second video download progress:" << i << endl;
    }
    cout << "The second video download is complete..." << endl;
}
void process()
{
    cout << "Start processing two videos" << endl;
}

int main()
{
    cout << "The main thread starts running\n";
    std::thread d2(download2);
    download1();
    d2.join();
    process();
}

Now it takes 50ms to download video 1 and 80ms to download video 2. When video 1 is downloaded, it can be processed together only after Video 2 is downloaded. To achieve this purpose, a line of code is added: d2.join().

In this scenario, we make two things clear:

  • Who called the join() function? The d2 thread object calls the join () function, so you must wait for the download task of d2 to end before the d2.join() function can be returned.
  • In which thread environment did d2 call the join() function? d2 calls the join () function in the environment of the main thread, so the main thread has to wait for the d2 thread to finish its work, otherwise the main thread will always be in the block state; What should not be confused here is that the real task (download) of d2 is done in another thread, but the action of d2 calling the join () function is done in the main thread environment.     The download task of d2 is done in its own sub thread, but d2 calls the join () function in the main thread environment.

Posted by Steffen on Sun, 21 Nov 2021 01:32:56 -0800