线程池的C ++ std :: thread停止条件

时间:2012-08-16 02:32:59

标签: c++ multithreading

我正在编写一个利用线程池的程序,以搜索指定扩展名的文件以匹配正则表达式。

我的线程池看起来像这样:

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中的所有项都已完成。任何想法都会受到赞赏。

2 个答案:

答案 0 :(得分:1)

我建议有一个线程(可能是产生文件处理线程的相同线程)专用于执行递归文件系统搜索匹配文件;它可以将文件添加到工作队列中,文件搜索线程可以从中查找工作。您可以使用条件变量来协调它。

正如您所发现的那样,协调关闭有点棘手。在文件系统搜索线程完成其搜索之后,它可以设置一些“刚刚完成排队的”标志,工作线程可见,然后通知它们全部唤醒并尝试处理另一个文件:如果他们发现文件/工作队列为空他们退出然后,filesystem-search线程加入所有worker。

答案 1 :(得分:0)

关于Tony回答评论中的更新问题,我建议有两种任务:一种用于递归地探索子目录,一种用于grep。您需要SynQueue<TaskBase>TaskSubDir: TaskBaseTaskGrep: TaskBaseTaskBase有一个虚拟界面功能Run()。然后,线程可以从SynQueue反复弹出,并调用TaskBase::Run()

  1. 如果它有TaskSubDir,那么它会找到 给定路径中的子目录和文件: (a)如果它是一个文件夹,则将一个新的TaskSubDir子目录添加到SynQueue,以便用线程池递归搜索文件夹; (b)如果是匹配的文件 扩展,然后它将TaskGrep推送到SynQueue
  2. 如果有TaskGrep,则会执行SearchFile
  3. 如果队列为空,break不在工作人员职能范围内。
  4. 这样做,您不需要有2个队列,并且在启动grep队列之前等待子目录队列完成。

    回答你的问题:要确定加入条件,你需要做的就是等待所有线程从工作函数break出来。

    最后注意:代码中的第一个_tasks.empty()不受互斥锁的保护,可能会遇到竞争条件。我建议你在SynQueue类中隐藏互斥锁和cond_var,并添加一个SynQueue::empty()成员函数(受互斥锁保护)。如果您担心效率,可能需要考虑使用无锁队列来替换SynQueue