[英]C++ std::thread stopping condition for thread pool
我正在编写一个利用线程池的程序,以便在指定扩展名的文件中搜索正则表达式的匹配项。
我的线程池如下所示:
for( int i = 0; i < _nThreads; ++i )
{
_threads.push_back( thread( &ThreadPool::GrepFunc, this ) );
}
运行函数如下所示:
void ThreadPool::GrepFunc()
{
// implement a barrier
while( !_done )
{
while( !_tasks.empty() )
{
fs::path task;
bool gotTask = false;
{
lock_guard<mutex> tl( _taskMutex );
if( !_tasks.empty() )
{
task = _tasks.front();
_tasks.pop();
gotTask = true;
}
}
if( gotTask )
{
if( std::tr2::sys::is_directory( task ) )
{
for( fs::directory_iterator dirIter( task ), endIter; dirIter != endIter; ++dirIter )
{
if( fs::is_directory( dirIter->path() ) )
{
{ lock_guard<mutex> tl( _taskMutex );
_tasks.push( dirIter->path() ); }
}
else
{
for( auto& e : _args.extensions() )
{
if( !dirIter->path().extension().compare( e ) )
{
SearchFile( dirIter->path() );
}
}
}
}
}
else
{
for( auto& e : _args.extensions() )
{
if( !task.extension().compare( e ) )
{
SearchFile( task );
}
}
}
}
}
}
}
从本质上讲,该程序从用户那里接收一个初始目录,并将在该目录和所有子目录中递归搜索与扩展名匹配的文件,以查找正则表达式匹配项。 我在弄清楚如何确定到达_done时的停止情况时遇到了麻烦。 我需要确保初始目录中的所有目录和文件都已被扫描,并且_tasks中的所有项都已完成,然后再加入线程。 任何想法将不胜感激。
我建议有一个线程(可能是产生文件处理线程的同一线程)专用于对匹配文件进行递归文件系统搜索。 它可以将文件添加到工作队列中,文件搜索线程可以从中获取工作。 您可以使用条件变量来对此进行协调。
如您所见,协调关机有点棘手。 在文件系统搜索线程完成搜索之后,它可以设置一些对工作线程可见的“仅完成队列中的内容”标志,然后向所有人发出信号以唤醒它们并尝试处理另一个文件:如果它们发现文件/工作队列为空他们退出。 然后,文件系统搜索线程加入所有工作程序。
关于您在Tony的答案评论中更新的问题,我建议执行2种任务:一项用于递归地浏览子目录,另一项用于grep。 您需要一个SynQueue<TaskBase>
, TaskSubDir: TaskBase
和TaskGrep: TaskBase
。 TaskBase
具有虚拟接口functon Run()
。 然后线程可以从SynQueue
反复弹出,并调用TaskBase::Run()
:
TaskSubDir
,那么它将在给定路径中找到子目录和文件:(a)如果它是一个文件夹,则将该子目录的新TaskSubDir
添加到SynQueue
,以便使用线程池 (b)如果它是具有匹配扩展名的文件,则它将TaskGrep
推送到SynQueue
。 TaskGrep
,则执行SearchFile
。 break
worker函数。 这样做,您不需要有2个队列并等待子目录队列完成才可以启动grep队列。
所以回答你的问题:确定加盟条件下,所有你需要做的是等待所有线程break
了工人的功能。
最后说明:代码中的第一个_tasks.empty()
不受互斥量保护,并且可能会出现竞争状况。 我建议您在SynQueue
类中隐藏互斥锁和cond_var,并添加一个SynQueue::empty()
成员函数(受互斥锁保护)。 如果您关注效率,则可能要考虑使用无锁队列来代替SynQueue
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.