Design de classe com rosca C ++ da classe não thread
-
20-09-2019 - |
Pergunta
Estou trabalhando em uma biblioteca fazendo codificação/decodificação de áudio. O codificador deve poder usar vários núcleos (ou seja, vários threads, usando a biblioteca Boost), se disponível. O que tenho agora é uma classe que executa todas as operações relevantes para codificação.
O próximo passo que quero dar é fazer essa aula rosqueada. Então, estou me perguntando como fazer isso.
Pensei em escrever uma classe de threads, criar n threads para n núcleos e depois chamar o codificador com os argumentos apropriados. Mas talvez seja um exagero e não há necessidade de outra classe, então vou usar a "interface do usuário" para criação de threads.
Espero que haja alguma sugestão.
Editar: Sou forçado a usar vários threads para o pré-processamento, criando estatísticas dos dados de entrada usando CUDA. Portanto, se houver vários cartões em um sistema, a única maneira de usá -los em paralelo é criar vários threads.
Exemplo: 4 arquivos, 4 diferente Unidades de cálculo (memórias separadas, ID de dispositivo exclusivo). Cada um dos arquivos deve ser executado em uma unidade de cálculo.
O que tenho agora é:
class Encoder {
[...]
public:
worker(T data, int devId);
[...]
}
Então eu acho que a melhor maneira é chamar o trabalhador de rosca de Main ()
boost::thread w1(&Encoder::worker, data0, 0);
boost::thread w2(&Encoder::worker, data1, 1);
boost::thread w3(&Encoder::worker, data2, 2);
boost::thread w4(&Encoder::worker, data3, 3);
e não implementar uma classe de threads.
Solução
Eu acho que o problema está mais em um nível de design, você pode elaborar um pouco sobre quais aulas você tem? Também trabalho no CUDA, e geralmente um cria uma interface (também conhecida como padrão de fachada) para usar a camada específica da arquitetura (CUDA).
Editar: Depois de ler a interface de atualização, acho que você está fazendo a coisa certa. Mantenha a lógica do codificador dentro da classe e use threads de impulso simples :: para executar diferentes unidades de trabalho. Basta preste atenção na segurança do encadeamento dentro dos métodos do codificador.
Outras dicas
Dê uma olhada em OpenMP, se o seu compilador suportar. Pode ser tão fácil quanto adicionar uma bandeira do compilador e pulverizar em alguns #pragma
s.
Sua sugestão atual funciona apenas se Encoder::worker
é static
. Presumo que seja esse o caso. Uma preocupação seria, se sua implementação atual suporta uma maneira de abortar graciosamente um trabalho de codificação. Suponho que existe algum método no seu código do formulário:
while( MoreInputSamples ) {
// Do more encoding
}
Isso pode ser modificado com algumas condições adicionais que verifica se os trabalhos receberam um sinal de abortamento. Eu trabalho muito em vídeo e gosto de ter minhas aulas de decodificador como essa:
class Decoder {
public:
void DoOneStepOfDecoding( AccessUnit & Input );
}
A saída geralmente vai para algum buffer de anel. Dessa forma, posso envolver isso facilmente em cenários únicos e multithread.
O código anterior
boost::thread w1(&Encoder::worker, data0, 0);
não é válido até que o trabalhador seja estático.
Há Boost.Task no cronograma de revisão que permite chamar de forma assíncrona qualquer chamável, como segue
boost::tasks::async(
boost::tasks::make_task( &Encoder::worker, data0, 0) ) );
Isso resulta em codificador :: trabalhador foi chamado em um threadpool padrão. A função retorna um identificador que permite saber quando a tarefa foi executada.