3

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

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

4 回答 4

6

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

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

于 2013-10-23T21:58:04.597 回答
4

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

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

于 2013-10-23T22:05:32.887 回答
1

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

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

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

于 2013-10-23T22:03:49.823 回答
1

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

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

一个建议:我不会将变量命名为Syncobject This,因为存在this关键字,所以它令人困惑。

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

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

于 2013-10-23T22:04:53.360 回答