Existe uma maneira de esse problema se beneficiar de uma solução com vários threads, em vez de um único thread?
Em uma entrevista, fui solicitado a resolver um problema usando vários threads. Parece-me que os vários threads não trazem benefícios.
Aqui está o problema:
Você recebe um parágrafo, que contém n número de palavras, e m tópicos. O que você precisa fazer é que cada thread imprima uma palavra e dê o controle para o próximo thread, dessa forma cada thread continuará imprimindo uma palavra, caso o último thread chegue, ele deve chamar o primeiro thread. A impressão será repetida até que todas as palavras sejam impressas no parágrafo. Finalmente, todos os threads devem sair normalmente. Que tipo de sincronização usará?
Sinto fortemente que não podemos tirar proveito dos threads aqui, mas acredito que o entrevistador está tentando medir minhas habilidades de sincronização. Estou faltando algo neste problema que faria com que vários threads tivessem valor?
Não há necessidade de código, basta colocar alguns pensamentos. Vou implementar sozinho.
fonte
Respostas:
Parece-me que eles estão levando você a uma solução de semáforo. Os semáforos são usados para sinalizar para outro segmento que é a vez deles. Eles são usados com muito menos frequência do que mutexes, o que eu acho que é por que eles acham que é uma boa pergunta para entrevista. É também por isso que o exemplo parece artificial.
Basicamente, você criaria
m
semáforos. Cada encadeamentox
espera no semáforo ex
depois é postado no semáforox+1
depois de fazer o seu trabalho. No pseudocódigo:fonte
Na minha opinião, essa é uma pergunta de entrevista fabulosa - pelo menos supondo (1) que o candidato tenha profundo conhecimento de encadeamento e (2) o entrevistador também tenha profundo conhecimento e esteja usando a pergunta para investigar o candidato. É sempre possível que o entrevistador esteja procurando uma resposta específica e restrita, mas um entrevistador competente deve procurar o seguinte:
Este último ponto é, na minha opinião, o mais importante. Novamente, com base na minha experiência, torna-se exponencialmente mais difícil depurar código encadeado se o encadeamento for misturado com a lógica do aplicativo (basta ver todas as perguntas do Swing no SO para exemplos). Acredito que o melhor código multithread é escrito como um código single-thread independente, com transferências claramente definidas.
Com isso em mente, minha abordagem seria fornecer a cada thread duas filas: uma para entrada e outra para saída. O encadeamento bloqueia durante a leitura da fila de entrada, retira a primeira palavra da sequência e passa o restante da sequência para a fila de saída. Algumas das características dessa abordagem:
Dito isto, ainda existem muitas áreas cinzentas que um entrevistador competente pode investigar:
Finalmente, se você possui experiência em programação simultânea, pode falar sobre algumas estruturas (por exemplo, Akka para Java / Scala) que já seguem esse modelo.
fonte
Às vezes, as perguntas da entrevista são realmente truques, destinadas a fazer você pensar sobre o problema que está tentando resolver. Fazer perguntas sobre uma pergunta é parte integrante da abordagem de qualquer problema, seja no mundo real ou em uma entrevista. Existem vários vídeos circulando na Internet sobre como abordar perguntas em entrevistas técnicas (procure particularmente o Google e talvez a Microsoft).
A aproximação de entrevistas com esse padrão de pensamento o levará a bombardear qualquer entrevista para qualquer empresa que valha a pena trabalhar.
Se você não acha que ganha muito (se houver algo com rosqueamento), diga isso a eles. Diga a eles por que você acha que não há nenhum benefício. Converse com eles. As entrevistas técnicas devem ser uma plataforma de discussão aberta. Você pode aprender algo sobre como isso pode ser útil. Não basta avançar cegamente tentando implementar algo que seu entrevistador lhe disse.
fonte
Primeiro, tokenize o parágrafo com delimitadores apropriados e adicione as palavras a uma Fila.
Crie um número N de threads e mantenha-o em um conjunto de threads.
Itere sobre o conjunto de encadeamentos e inicie o encadeamento e aguarde
a junção do encadeamento. E inicie o próximo segmento assim que o primeiro segmento terminar e assim por diante.
Cada thread deve apenas pesquisar a fila e imprimi-la.
Depois que todos os threads forem usados no pool de threads, inicie do início do pool.
fonte
Como você disse, não acho que esse cenário se beneficie muito, se é que existe um encadeamento. Provavelmente é mais lento que uma única implementação encadeada.
No entanto, minha resposta seria ter cada thread em um loop restrito tentando acessar um bloqueio que controla o acesso ao índice de matriz de palavras. Cada thread pega o bloqueio, obtém o índice, obtém a palavra correspondente da matriz, imprime, incrementa o índice e libera o bloqueio. Os encadeamentos são encerrados quando o índice está no final da matriz.
Algo assim:
Eu acho que isso deve atingir um segmento após outro requisito, mas a ordem dos segmentos não é garantida. Estou curioso para ouvir outras soluções também.
fonte
Use APIs de espera / sinal de condição para resolver esse problema.
Digamos que o primeiro thread escolha 1 palavra e, enquanto isso, descanse todos os threads aguardando um sinal. 1ª linha imprime a 1ª palavra e gera sinal para a próxima linha e, em seguida, a 2ª linha imprime a segunda palavra e gera sinal para a 3ª linha e assim por diante.
fonte
[Termos usados aqui talvez específicos para threads POSIX]
Também deve ser possível usar um mutex FIFO para resolver esse problema.
Onde usar:
Suponha que dois segmentos T1 e T2 estão tentando executar uma seção crítica. Ambos não têm muito o que fazer fora desta seção crítica e mantêm bloqueios por um bom tempo. Portanto, T1 pode bloquear, executar e desbloquear e sinalizar T2 para ativação. Porém, antes que T2 pudesse ativar e adquirir bloqueio, T1 recupera o bloqueio e a execução. Dessa forma, o T2 pode ter que esperar muito tempo antes de realmente obter o bloqueio ou não.
Como funciona / Como implementar:
Tenha um mutex para travar. Inicialize os Dados Específicos do Encadeamento (TSD) para cada encadeamento em um nó contendo o ID e o semáforo do encadeamento. Além disso, possui duas variáveis - de propriedade (TRUE ou FALSE ou -1), owner (ID do encadeamento do proprietário). Além disso, mantenha uma fila de garçons e um ponteiro waiterLast apontando para o último nó na fila de garçons.
operação de bloqueio:
operação de desbloqueio:
fonte
Pergunta interessante. Aqui está minha solução em Java usando SynchronousQueue para criar um canal de encontro entre threads:
fonte
Eu diria que esse tipo de pergunta é muito difícil de responder, porque pede a melhor maneira de fazer algo completamente estúpido. Meu cérebro simplesmente não funciona assim. Não consegue encontrar soluções para perguntas estúpidas. Meu cérebro diria imediatamente que, nessas condições, o uso de vários threads não faz sentido, então eu usaria um único thread.
Depois, eu pediria que eles fizessem uma pergunta do mundo real sobre a segmentação ou deixassem que eu desse um exemplo do mundo real de uma segmentação séria.
fonte