std::thread 不是全局变量,但在到达创建它的函数末尾时不会超出范围?
Posted
技术标签:
【中文标题】std::thread 不是全局变量,但在到达创建它的函数末尾时不会超出范围?【英文标题】:std::thread that isn't a global variable but doesn't go out of scope when the end of the function that created it is reached? 【发布时间】:2018-09-06 04:40:58 【问题描述】:所以我遇到了一些似乎违背了std::thread
目的的东西,或者至少使它不那么方便了。
假设我想生成一个std::thread
来执行一次任务,之后不想再担心它。我在函数末尾附近创建了这个thread
,所以std::thread
很快就会超出范围,就我而言,可能是在thread
仍在运行时。这会产生几个解决方案(或至少我知道的)的问题。
我可以:
A) 将std::thread
设为全局变量,这样它就不会超出范围。
B) 在std::thread
上调用join()
,这违背了产生线程的目的。
还有其他的(希望是更好的)处理这种情况的方法吗?
【问题讨论】:
如果您不关心任务,为什么要首先启动它?std::thread
对象被销毁有什么问题?就像std::fstream
是文件一样,它们都是线程,它们都只是资源的句柄,而不是资源本身。另外,为什么它是 std::thread
很重要,你将如何处理不同类型的对象,比如 std::string
?
这里的问题是你永远不知道任务何时完成,或者它是否完成。因此,您的程序甚至可能在您的线程开始工作之前终止。这种方法主要适用于可选任务。此外,如果您的任务在没有任何同步的情况下修改全局数据,您就会面临各种令人讨厌的后果。
@EdwardSeverinsen 当然。我只是想说,我认为最好将多线程方面排除在管理对象生命周期之外。您正在寻找的只是存储线程对象的地方。它可以是任何对象,即使不涉及线程,也可以处理它的生命周期。将问题分解为更小的部分。
销毁std::thread
“导致在线程上调用终止()”并非如此,它“导致终止()被调用”,终止您的进程。
【参考方案1】:
你想要的是std::thread::detach。
它将实际的执行线程和std::thread
对象解耦,允许您在不加入线程的情况下销毁它。
【讨论】:
你必须小心分离的线程。你如何处理异常?如何知道/控制线程是否正在运行或已完成? @AchimGuetleinstd::thread
s 在抛出异常时终止,无论它们是否分离。要与线程进行通信,您拥有所有常用机制 - std::future
、std::mutex
、原子等 - 同样,它们不依赖于 std::thread
对象
你是对的。有办法处理所有这些问题。我的观点是,如果你不解决这些问题,你可能会遇到麻烦。如果你这样做,使用std::async
返回的std::future
可能会更简单【参考方案2】:
您可以使用std::async
。
async 异步运行函数 f (可能在一个单独的线程中,它可能是线程池的一部分)并返回一个 std::future ,它最终将保存该函数调用的结果。
由于你没有提到需要获取线程的结果,所以没有必要获取future。
正如 cmets 中所指出的,std::future 的析构函数在任何情况下都会阻塞,因此您必须将其移动到某个全局对象(并手动管理未使用期货的删除),或者您可以将其移动到异步调用函数的本地范围。
【讨论】:
他没有提到他想得到线程的结果。所以没有必要获得未来。 但是如果 async 的返回值没有分配给未来呢? @P.W 也阻塞,见herestd::async
的返回值是 std::future
,其析构函数会阻塞。【参考方案3】:
其他首选选项是允许线程使用任务队列中的任务。为此,将作业拆分为任务块并提供给工作线程。为避免轮询,请选择 condition_variable。
std::thread([&]()
while(running) // thread loop
// consume tasks from queue
).detach();
【讨论】:
以上是关于std::thread 不是全局变量,但在到达创建它的函数末尾时不会超出范围?的主要内容,如果未能解决你的问题,请参考以下文章
可以从 Windows DLL 中的全局变量创建/销毁 std::threads 吗?