0

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

我的线程池如下所示:

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 中的所有项目都已完成。任何想法都会非常感激。

4

2 回答 2

1

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

正如您所发现的,协调关机有点棘手。文件系统搜索线程完成搜索后,它可以设置一些对工作线程可见的“刚刚完成排队的内容”标志,然后向它们发出信号以唤醒并尝试处理另一个文件:如果他们发现文件/工作队列为空他们退出。然后文件系统搜索线程加入所有工作人员。

于 2012-08-16T02:55:30.750 回答
0

关于您在托尼回答的评论中更新的问题,我建议有两种任务:一种用于递归探索子目录,另一种用于 grep。你需要一个SynQueue<TaskBase>,TaskSubDir: TaskBaseTaskGrep: TaskBase. TaskBase具有虚拟接口功能Run()。然后线程可以从重复弹出SynQueue,并调用TaskBase::Run()

  1. 如果它得到 a TaskSubDir,那么它将在给定路径中找到子目录和文件: (a) 如果它是一个文件夹,则将新TaskSubDir的子目录添加到SynQueue,以便使用线程池递归搜索文件夹;(b) 如果它是具有匹配扩展名的文件,则将 a 推TaskGrep送到SynQueue.
  2. 如果它得到一个TaskGrep,那么它执行SearchFile.
  3. 如果队列为空,则break退出工作函数。

这样做,您不需要有 2 个队列并在启动 grep 队列之前等待子目录队列完成。

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

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

于 2012-08-16T04:04:53.703 回答