如何知道分离的 std::thread 是不是已完成执行?
Posted
技术标签:
【中文标题】如何知道分离的 std::thread 是不是已完成执行?【英文标题】:How to know whether detached std::thread has finished its execution?如何知道分离的 std::thread 是否已完成执行? 【发布时间】:2019-02-18 15:22:57 【问题描述】:我有一个类似下面的函数,其中线程通过使用 std::lock_guard 互斥锁获取锁并通过 ofstream 写入文件。
当当前文件大小增加最大大小时,我创建一个独立线程来压缩文件并终止。
如果日志文件很大(比如 ~500MB),压缩大约需要 25 秒以上。 我分离了压缩线程,因为没有其他线程(或主线程)想要等待这个线程完成。
但我需要知道压缩线程在执行以下行之前没有运行:
_compress_thread(compress_log, _logfile).detach();
示例代码sn-p:
void log (std::string message)
// Lock using mutex
std::lock_guard<std::mutex> lck(mtx);
_outputFile << message << std::endl;
_outputFile.flush();
_sequence_number++;
_curr_file_size = _outputFile.tellp();
if (_curr_file_size >= max_size)
// Code to close the file stream, rename the file, and reopen
...
// Create an independent thread to compress the file since
// it takes some time to compress huge files.
if (the_compress_thread_is_not_already_running) //pseudo code
_compress_thread(compress_log, _logfile).detach();
在上述if
条件下,即the_compress_thread_is_not_already_running
,如何确定压缩线程没有运行?
void * compress_log (std::string s)
// Compress the file
// ...
【问题讨论】:
如果您需要知道线程是否仍在运行,那么听起来您并不真正想要detach
。 detach
通常表示设计存在问题。语句“我需要知道压缩线程没有运行”意味着应该有1个压缩线程,这与使用detach
相反,并且与语句“没有其他线程”相反(或主)想要等待这个线程完成”.
您也可以使用std::async
并保留一个未来的对象。然后你可以使用它来确保在你再次调用之前之前的调用已经结束。
为什么会有问题?
std::thread _compress_thread(compress_log, _logfile);
是一个局部变量,对您的函数来说是局部变量,并且总是创建一个新对象。它从不引用现有线程。
@C_user5 然后detach
与您想要做的完全相反。 join
在您为其分配新值之前使用它。 detach
的意思是“我不关心这个线程,它什么时候完成,或者即使它完成”,这在你的情况下是不正确的。编辑:但是正如 cmets 和答案所指出的那样,最好使用 std::async
并存储 std::future
来代替。 std::thread
旨在用作低级基本对象。它的设计不是为了易于使用。如果您想异步运行任务(压缩文件),请使用std::async
。这就是它的用途。
【参考方案1】:
无法检测分离的执行线程是否已终止。
如果你出于某种原因需要保证最多一个线程同时压缩,那么一个简单的解决方案是使用std::async
。它返回一个 future 对象。您可以查询未来对象关联的回调是否已完成。通过在函数末尾修改共享变量(注意共享访问必须同步),使用分离线程可以以较少结构化的方式实现相同的效果。
另一种方法是不断保持压缩线程的活动状态,但只要没有工作要做就阻止它。可以使用条件变量通知线程开始其工作,一旦完成,继续阻塞直到下一次通知。
附:您可能希望先关闭文件流,重命名文件,然后在您持有锁时重新打开,以便其他线程可以在之前的日志(现在在重命名的文件中)被压缩时继续登录到新文件。
【讨论】:
谢谢。在原始代码中,我已经在做以下事情:“关闭文件流,重命名文件,然后重新打开”。为了便于阅读,将它们从代码 sn-p 中删除。 对于“通过在函数末尾修改共享变量来使用分离线程(注意共享访问必须同步)”的方法,假设我使用共享变量并使用相同的保护它互斥体,即std::lock_guard<std::mutex> lck(mtx)
,仍然有可能正在清理压缩线程(在修改共享变量之后),而另一个线程最终执行_compress_thread(compress_log, _logfile).detach();
。不是吗。。
@C_user5 我不会使用相同的互斥锁。我建议改用原子变量。也就是说,我首先不推荐这种方法,因为std::async
更简单。 still there is a possibility that the compress thread's clean up is in progress
当然。同样适用于使用std::async
。如果这对您来说是个问题,那么恒定压缩线程方法可能对您有好处。也就是说,我不明白为什么会出现问题。以上是关于如何知道分离的 std::thread 是不是已完成执行?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 QThread 创建一个分离的线程,就像在 std::thread 中一样