boost :: thread_group - Tudo bem ligar para create_thread após join_all?
-
21-09-2019 - |
Pergunta
Eu tenho a seguinte situação:
Crie uma instância do Boost :: Thread_group e, em seguida, crio threads para processamento paralelo em alguns dados e junto-me aos threads.
Inicialmente, criei os threads para todos os x elementos de dados, assim:
// begin = someVector.begin();
// end = someVector.end();
// batchDispatcher = boost::function<void(It, It)>(...);
boost::thread_group processors;
// create dispatching thread every ASYNCH_PROCESSING_THRESHOLD notifications
while(end - begin > ASYNCH_PROCESSING_THRESHOLD)
{
NotifItr split = begin + ASYNCH_PROCESSING_THRESHOLD;
processors.create_thread(boost::bind(batchDispatcher, begin, split));
begin = split;
}
// create dispatching thread for the remainder
if(begin < end)
{
processors.create_thread(boost::bind(batchDispatcher, begin, end));
}
// wait for parallel processing to finish
processors.join_all();
Mas tenho um problema com isso: quando tenho muitos dados, esse código está gerando muitos threads (> 40 threads), o que mantém o processador ocupado com contextos de troca de linhas.
Minha pergunta é a seguinte: é possível chamar Create_thread no Thread_group depois a chamada para join_all.
Ou seja, posso mudar meu código para isso?
boost::thread_group processors;
size_t processorThreads = 0; // NEW CODE
// create dispatching thread every ASYNCH_PROCESSING_THRESHOLD notifications
while(end - begin > ASYNCH_PROCESSING_THRESHOLD)
{
NotifItr split = begin + ASYNCH_PROCESSING_THRESHOLD;
processors.create_thread(boost::bind(batchDispatcher, begin, split));
begin = split;
if(++processorThreads >= MAX_ASYNCH_PROCESSORS) // NEW CODE
{ // NEW CODE
processors.join_all(); // NEW CODE
processorThreads = 0; // NEW CODE
} // NEW CODE
}
// ...
Quem tem experiência com isso, obrigado por qualquer insight.
Solução
Eu acredito que isso não é possível. A solução que você deseja pode ser realmente para implementar um Produtor-Consumidor ou um mestre-trabalhador (encadeamento principal 'mestre' divide o trabalho em várias tarefas de tamanho fixo, cria pool de threads 'trabalhadores' e envia uma tarefa para cada trabalhador até que todas as tarefas sejam realizadas).
Essas soluções exigirão alguma sincronização por meio de semáforos, mas eles equalizarão bem o desempenho que você pode criar um thread para cada núcleo disponível na máquina, evitando o desperdício de tempo nos interruptores de contexto.
Outra opção não tão boa e de grande porra é ingressar em um tópico de cada vez. Você pode ter um vetor com 4 threads ativos, ingressar um e criar outro. O problema dessa abordagem é que você pode desperdiçar o tempo de processamento se suas tarefas forem heterogêneas.