【问题标题】:std::thread when is thread executed?std::thread 线程何时执行?
【发布时间】:2013-10-24 06:15:36
【问题描述】:

我浏览了一些线程教程,但对一件事感到好奇。

std::thread Child([](){ std::cout << "When am I executed?" << std::endl << std::endl; });

//Some other code

Child.join();

//I'm guessing now my thread would be running

线程是在我调用join() 时执行的,还是在创建线程和我调用join 之间的某个时间运行?如果在调用join() 时执行它,只是为了检查我的理解,它会告诉该部分执行并且您的程序在主线程上继续,最终子线程在主线程使用的同一内存上做了一些工作?

如果我想为一个泛型类创建一个包装器,我想做如下的事情,但我似乎无法完全弄清楚。我对根据内存管理线程感到困惑。

class Sync {
private:
    int val;

public:
    Sync() : val(0) {}
    void Inc() {val++}
    int Value() { return val; }
};

class Async {
private:
    Sync Foo;
    std::mutex mtx;
    std::vector<std::thread*> Children;
public:
    //I would need a new thread each time I called Inc
    void Inc() { 
        Children.push_back(new std::thread([&]() {
            mtx.lock();
            Foo.Inc();
            mtx.unlock();
        }));


    }
    //But how do I know when it is safe to delete Child?  
    int Value() { 
        for(auto& thds : Children) {
            thds->join();
            delete thds; 
        }
        Children.clear();
        return Foo.Value(); }
};

我正在考虑适当的位置可能在线程函数的末尾,因为不再需要 Child 但是如果您尝试从其内部销毁线程会发生什么?我猜这听起来像个坏主意。我怎么知道什么时候可以删除我的话题?有更好的方法吗?

修改了上面的代码以反映下面的建议。

我现在意识到教程中关于引发异常的内容,所以我应该使用互斥锁而不是 mtx.lock() 我猜。

【问题讨论】:

    标签: c++ multithreading


    【解决方案1】:

    join 的目的本质上是等待线程完成。所以一旦Child-&gt;join(); 返回,你的线程就完成了。当然,您也可以在析构函数中执行Child-&gt;join() [或在其他某个时间点,只要确保它在某个时间点被调用]。

    请注意,线程将在实际创建时间和连接结束之间的某个时间点开始运行。没有办法知道什么时候会发生。如果您的系统上已经有很多线程在运行,那么时间将在所有线程之间分配,您的线程可能会在几秒钟内无法运行。另一方面,如果有一个 CPU 坐在那里“玩弄它的手指”,它很可能会在主线程退出 new std::thread(...) 构造之前启动 [因为 std::thread 在线程正确运行之前不会返回已创建,并且一些数据存储在线程对象中,因此当您到达Child-&gt;join() 时,线程很可能已经完成。如果不知道系统处于什么状态,就无法判断它是这些选项中的哪一个。

    【讨论】:

    • 那么线程一创建就开始运行?此外,我可以在加入通话后调用删除。谢谢你
    • 是的,我刚刚编辑了答案,以澄清线程可能在您完成创建之前开始,或者在稍后的某个时间开始。这完全取决于系统中有多少 CPU/内核以及系统中的整体负载。
    【解决方案2】:

    操作系统很重要,但它相当普遍。线程被调度 执行。操作系统何时开始实际运行是完全不可预测的。在今天普遍可用的多核机器上“快速”运行的可能性很大。

    thread::join() 只是确保线程完成执行。你永远不会真正写出这样的代码,启动一个线程然后等待它完成是完全没有意义的。还不如直接执行线程的代码。同样的结果,不会因为创建线程而使操作系统陷入困境。

    【讨论】:

    • 我现在可以看到调用 join 相同的功能与同步版本相同。既然我更好地理解了这一点,我将不得不多考虑一下。谢谢
    【解决方案3】:

    您无法知道您的线程将以何种顺序或在哪个核心上运行。

    一个 posix 线程基本上被 linux 视为一个与另一个共享其堆的进程。 内核将调度它们并决定使用哪个内核。例如,查看生成的(受保护的)程序集,您将看不到任何“多核/多线程编程”,因为这是在内核级别完成的。

    这就是存在诸如连接之类的函数以及诸如互斥体/信号量之类的工件的原因。处理比赛条件和其他相关问题。

    【讨论】:

      【解决方案4】:

      当我调用 join() 时线程正在执行还是正在运行 在创建线程和我调用 join 之间的某个时间?

      线程在创建线程后执行(启动),具体取决于可能需要一些时间的可用资源。 join() 方法等待(阻塞)直到线程完成它的工作。

      一个建议:我不会将变量命名为Sync 对象This,这令人困惑,因为存在this 关键字。

      Async::Inc() 中调用join() 后,您可以安全地删除std::thread 对象,而且您不需要将引用存储为成员变量,它只在该函数中使用。

      您还可以查看&lt;atomic&gt; 标头、std::atomic&lt;int&gt;std::atomic_int

      【讨论】:

        猜你喜欢
        • 2018-01-02
        • 2020-02-13
        • 1970-01-01
        • 1970-01-01
        • 2012-04-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多