[英]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.