std :: thread什么时候执行线程?

时间:2013-10-23 21:48:55

标签: c++ multithreading

我已经浏览了一些线程教程,但我很好奇一件事。

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()我猜。

4 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:4)

操作系统很重要,但它相当普遍。线程预定执行。当操作系统到处实际运行时,完全无法预测。你可以在拥有多个内核的机器上“快速”获得不错的赔率,这在今天是普遍可用的。

thread :: join()只是确保线程完成执行。你永远不会实际编写这样的代码,启动一个线程然后等待它完成是完全没有意义的。也可以直接执行线程的代码。通过创建线程而不会影响操作系统,结果相同。

答案 2 :(得分:1)

您无法知道线程将以何种顺序或核心运行。

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

这就是为什么存在连接等函数和互斥锁/信号量等工件的原因。照顾种族状况和其他相关的东西。

答案 3 :(得分:1)

  

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

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

建议:我不会将变量命名为Sync对象This,因为存在this关键字,所以会让人感到困惑。

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

您还可以查看<atomic>标题,std::atomic<int>std::atomic_int