我正在编写一个利用线程池的程序,以搜索指定扩展名的文件以匹配正则表达式。
我的线程池看起来像这样:
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中的所有项都已完成。任何想法都会受到赞赏。
答案 0 :(得分:1)
我建议有一个线程(可能是产生文件处理线程的相同线程)专用于执行递归文件系统搜索匹配文件;它可以将文件添加到工作队列中,文件搜索线程可以从中查找工作。您可以使用条件变量来协调它。
正如您所发现的那样,协调关闭有点棘手。在文件系统搜索线程完成其搜索之后,它可以设置一些“刚刚完成排队的”标志,工作线程可见,然后通知它们全部唤醒并尝试处理另一个文件:如果他们发现文件/工作队列为空他们退出然后,filesystem-search线程加入所有worker。
答案 1 :(得分:0)
关于Tony回答评论中的更新问题,我建议有两种任务:一种用于递归地探索子目录,一种用于grep。您需要SynQueue<TaskBase>
,TaskSubDir: TaskBase
和TaskGrep: TaskBase
。 TaskBase
有一个虚拟界面功能Run()
。然后,线程可以从SynQueue
反复弹出,并调用TaskBase::Run()
:
TaskSubDir
,那么它会找到
给定路径中的子目录和文件:
(a)如果它是一个文件夹,则将一个新的TaskSubDir
子目录添加到SynQueue
,以便用线程池递归搜索文件夹; (b)如果是匹配的文件
扩展,然后它将TaskGrep
推送到SynQueue
。 TaskGrep
,则会执行SearchFile
。break
不在工作人员职能范围内。这样做,您不需要有2个队列,并且在启动grep队列之前等待子目录队列完成。
回答你的问题:要确定加入条件,你需要做的就是等待所有线程从工作函数break
出来。
最后注意:代码中的第一个_tasks.empty()
不受互斥锁的保护,可能会遇到竞争条件。我建议你在SynQueue
类中隐藏互斥锁和cond_var,并添加一个SynQueue::empty()
成员函数(受互斥锁保护)。如果您担心效率,可能需要考虑使用无锁队列来替换SynQueue
。