【问题标题】:What happens when a thread is constructed, and how is the thread executed构造线程时会发生什么,以及线程是如何执行的
【发布时间】:2021-07-17 22:11:11
【问题描述】:

我对多线程完全陌生,在理解多线程的实际工作原理方面有点困难。

让我们考虑以下代码示例。该程序只是将文件名作为输入并计算其中的小写字母数量。

#include <iostream>
#include <thread>
#include <mutex>
#include <memory>
#include <vector>
#include <string>
#include <fstream>
#include <ctype.h>

class LowercaseCounter{
public:
    LowercaseCounter() :
        total_count(0)
    {}
    void count_lowercase_letters(const std::string& filename)
    {
        int count = 0;
        std::ifstream fin(filename);
        char a;
        while (fin >> a)
        {
            if (islower(a))
            {
                std::lock_guard<std::mutex> guard(m);
                ++total_count;
            }
        }
    }
    void print_num() const
    {
        std::lock_guard<std::mutex> guard(m);
        std::cout << total_count << std::endl;
    }
private:
    int total_count;
    mutable std::mutex m;
};
int main(){
    std::vector<std::unique_ptr<std::thread>> threads;
    LowercaseCounter counter;
    std::string line;
    while (std::cin >> line)
    {
        if (line == "exit")
            break;
        else if (line == "print")
            counter.print_num(); //I think that this should print 0 every time it's called.
        else
            threads.emplace_back(new std::thread(&LowercaseCounter::count_lowercase_letters, counter, line));
    }
    for (auto& thread : threads)
        thread->join();
}

首先,我认为counter.print_num() 的输出将打印 0,因为线程尚未“加入”以执行函数。然而,事实证明程序运行正常,counter.print_num() 的输出不是 0。所以我问了自己以下问题。

构造线程时实际发生了什么?

如果上面的程序运行正常,那么线程必须在创建时执行,那么std::thread::join方法是做什么的?

如果线程是在创建的时候执行的,那么在这个例子中使用多线程有什么意义呢?

提前致谢。

【问题讨论】:

  • 听起来你觉得线程更像协程。线程开始在创建时执行,join() 一直等到线程结束。除此之外,它与所有其他线程并行运行,可能在不同的 CPU 内核上。
  • @Frank 如果线程有一个指定的 start 时间(在构造时),那么我想它应该有一个指定的 end 时间。 join() 等待线程结束是什么意思?
  • 线程在其入口点函数返回后简单地结束,就像程序在到达main() 的末尾时结束一样。
  • @Frank 那么如果我不为每个线程调用join() 方法会发生什么。

标签: c++ multithreading


【解决方案1】:

您似乎认为程序一次只能运行一个线程,并且它需要中断正在执行的任何操作才能执行线程的代码。事实并非如此。

您可以将线程视为一个完全独立的程序,它碰巧与创建它的程序共享内存和资源。您作为参数传递的函数是该程序的“main()”,用于每个意图和目的。在 Linux 中,线程字面意思是独立的进程,但就 C++ 而言,这只是一个实现细节。

因此,在具有抢先式多任务处理的现代操作系统中,就像多个程序可以同时运行一样,线程也可以同时运行。请注意,我说可以,由编译器和操作系统决定何时为每个线程分配 CPU 时间。

那么 std::thread::join 方法是做什么的呢?

它只是等到线程完成。

如果我不为每个线程调用 join() 方法会发生什么

它会在到达main() 的末尾时崩溃,因为尝试退出程序而不加入非分离线程被视为错误。

【讨论】:

    【解决方案2】:

    如你所说,在 c++ 中,线程在创建时执行,所有std::thread::join 所做的只是等待线程完成执行。

    在您的代码中,所有线程将在循环中同时开始执行,然后主线程将等待每个线程在下一个循环中完成执行。

    【讨论】:

    • 如果线程有一个指定的开始时间(在构造时),那么我想它应该有一个指定的结束时间。你说 join() 等到线程结束是什么意思?
    • @KarenBaghdasaryan 为什么线程要有指定的结束时间?假设一个线程调用一个函数,该函数仅在股票超过特定值时退出,主线程应该不知道另一个线程何时结束执行。现在,如果主线程想要在该线程结束后执行代码only,您将在该线程上调用join 并等待它结束。总而言之,join 基本上是暂停主线程,直到加入的线程执行完毕。
    • 哦,非常感谢!
    • 你的意思是,暂停调用 join 的线程,直到加入的线程退出。任何线程都可以加入另一个线程。主线程与任何事情无关。
    猜你喜欢
    • 2017-11-18
    • 1970-01-01
    • 2019-11-05
    • 2014-08-31
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 2017-02-14
    • 2013-12-01
    相关资源
    最近更新 更多