2016-12-20 2 views
0

Я работаю над программой, которая печатает регулярные выражения из нескольких потоков, ищущих файловую систему, и каждый поток добавляет свой идентификатор в очередь и уведомляет основной поток о том, что есть некоторые потоки, которые нужно удалить из пула потоков который является std :: vector.Правильная гранулярность для блокировки Mutex

В этот момент я отпираю и блокирую мьютексы всякий раз, когда выполняю операцию над ресурсом, который необходимо защитить. Мне кажется, что я чувствую, что все это неправильно, и что я слишком разборчив. Будет ли лучше блокировать мьютексы перед входом в цикл while, разблокировать после того, как он выскочил в очередь, а затем снова заблокировал его до ! Finished_threads.empty() вызывается на следующей итерации?

void RegexSearch::Run() 
{ 
    running = true; 
    search_pool.push_back(std::thread([&] { StartPrint(); })); 

    /* 
    Get directories and create another thread for each subdirectory while there are 
    less threads than maximum in the pool. 
    */ 

    fs::path searchDir(directory); 

    for (const auto& dir : searchDir) 
    { 
     if (search_pool.size() >= MAX_THREADS) 
     { 
      std::unique_lock<std::mutex> lck(mu, std::defer_lock); 
      // Wait to be notified that thread is finished execution and another can start. 
      max_thread_cond.wait(lck); 

      lck.lock(); 
      while (!finished_threads.empty()) 
      { 
       lck.unlock(); 

       lck.lock(); 
       std::thread::id remove_thread = finished_threads.front(); 
       lck.unlock(); 

       lck.lock(); 
       finished_threads.pop(); 
       lck.unlock(); 

       std::remove_if(search_pool.begin(), search_pool.end(), [&remove_thread](const std::thread::id &t) { return remove_thread == t; }); 
       lck.lock(); 
      } 
     } 
    } 
} 

ответ

1

Вы, конечно, должны иметь блокировку от теста для !empty(), пока вы не удалили элемент из очереди. В противном случае несколько потоков могут попытаться удалить один и тот же элемент - возможно, последний.

Я также вижу, что push_back в начале функции не защищен. Если может быть несколько потоков, обращающихся к search_pool, их необходимо также охранять.

+0

О, это имеет смысл. Нет потоков, обращающихся к thread_pool до вызова Run(). Нужно ли это блокировать с помощью мьютекса? – CanadaIT

+0

Стандартные контейнеры не являются потокобезопасными, поэтому, если больше потоков может получить доступ к контейнеру во время его обновления, должна быть блокировка. Если вы только читаете или есть только один поток, обращающийся к определенному контейнеру, вы все равно в безопасности. –

Смежные вопросы