Dans une interview, on m'a demandé de résoudre un problème en utilisant plusieurs threads. Il me semble que les multiples threads ne présentent aucun avantage.
Voici le problème:
On vous donne un paragraphe, qui contient n nombre de mots, on vous donne m fils. Ce que vous devez faire, c'est que chaque thread doit imprimer un mot et donner le contrôle au thread suivant, de cette façon, chaque thread continuera à imprimer un mot, au cas où le dernier thread arriverait, il devrait invoquer le premier thread. L'impression se répétera jusqu'à ce que tous les mots soient imprimés dans le paragraphe. Enfin, tous les threads devraient se terminer correctement. Quel type de synchronisation utilisera?
Je pense fermement que nous ne pouvons pas tirer parti des discussions ici, mais je crois que l'intervieweur essaie de mesurer mes compétences en synchronisation. Suis-je en train de manquer quelque chose dans ce problème qui donnerait de la valeur à plusieurs threads?
Pas besoin de code, mettez juste quelques réflexions. Je mettrai en œuvre par moi-même.
Il me semble qu'ils vous conduisent vers une solution de sémaphore. Les sémaphores sont utilisés pour signaler à un autre thread que c'est leur tour. Ils sont utilisés beaucoup moins fréquemment que les mutex, ce qui explique pourquoi je pense que c'est une bonne question d'entrevue. C'est aussi pourquoi l'exemple semble artificiel.
Fondamentalement, vous créez des sémaphores m
. Chaque thread x
attend le sémaphore x
puis publie sur le sémaphore x+1
après avoir fait son truc. En pseudocode:
loop:
wait(semaphore[x])
if no more words:
post(semaphore[(x+1) % m])
exit
print Word
increment current Word pointer
post(semaphore[(x+1) % m])
À mon avis, il s'agit d'une fabuleuse question d'entrevue - au moins en supposant (1) que le candidat devrait avoir une connaissance approfondie du filetage, et (2) l'intervieweur possède également une connaissance approfondie et utilise la question pour sonder le candidat. Il est toujours possible que l'enquêteur recherche une réponse précise et précise, mais un enquêteur compétent doit rechercher les éléments suivants:
Ce dernier point est, à mon avis, le plus important. Encore une fois, d'après mon expérience, il devient exponentiellement plus difficile de déboguer du code threadé si le threading est mélangé avec la logique d'application (regardez simplement toutes les questions Swing sur SO pour des exemples). I estiment que le meilleur code multi-thread est écrit en tant que code mono-thread autonome, avec des transferts clairement définis.
Dans cet esprit, mon approche serait de donner à chaque thread deux files d'attente: une pour l'entrée, une pour la sortie. Le thread se bloque lors de la lecture de la file d'attente d'entrée, enlève le premier mot de la chaîne et transmet le reste de la chaîne à sa file d'attente de sortie. Certaines des caractéristiques de cette approche:
Cela dit, il y a encore beaucoup de zones grises qu'un enquêteur compétent peut sonder:
Enfin, si vous avez de l'expérience en programmation concurrente, vous pourriez parler de certains cadres (par exemple, Akka pour Java/Scala) qui suivent déjà ce modèle.
Les questions d'entrevue sont parfois en fait des questions pièges, destinées à vous faire réfléchir sur le problème que vous essayez de résoudre. Poser des questions sur une question fait partie intégrale de l'approche tout d'un problème, que ce soit dans le monde réel ou dans une interview. Il existe un certain nombre de vidéos circulant sur Internet sur la façon d'aborder les questions dans les entretiens techniques (recherchez en particulier Google et peut-être Microsoft).
"Essayez juste de répondre, et sortez de là ..."
Approcher les entretiens avec ce schéma de pensée vous conduira à bombarder n'importe quel entretien pour toute entreprise qui vaut la peine de travailler.
Si vous ne pensez pas que vous gagnez beaucoup (si quelque chose de filetage), dites-le-leur. Dites-leur pourquoi vous ne pensez pas qu'il y ait un avantage. Discutez avec eux. Les entretiens techniques sont censés être une plateforme de discussion ouverte. Vous pourriez finir par apprendre quelque chose sur la façon dont cela peut être utile. Ne vous contentez pas d'aller de l'avant aveuglément en essayant de mettre en œuvre quelque chose que votre intervieweur vous a dit de faire.
Comme vous l'avez dit, je ne pense pas que ce scénario profite grandement, voire pas du tout, du threading. C'est probablement plus lent qu'une implémentation à un seul thread.
Cependant, ma réponse serait d'avoir chaque thread dans une boucle serrée essayant d'accéder à un verrou qui contrôle l'accès à l'index du tableau Word. Chaque thread saisit le verrou, obtient l'index, obtient le mot correspondant du tableau, l'imprime, incrémente l'index puis libère le verrou. Le thread se ferme lorsque l'index se trouve à la fin du tableau.
Quelque chose comme ça:
while(true)
{
lock(index)
{
if(index >= array.length())
break;
Console.WriteLine(array[index]);
index++;
}
}
Je pense que cela devrait atteindre l'un thread après une autre exigence, mais l'ordre des threads n'est pas garanti. Je suis curieux d'entendre aussi d'autres solutions.
Commencez par symboliser le paragraphe avec les délimiteurs appropriés et ajoutez les mots à une file d'attente.
Créez N nombre de threads et conservez-le dans un pool de threads.
Itérer sur le pool de threads et démarrer le thread et attendre la
thread à rejoindre. Et commencez le fil suivant une fois le premier fil terminé et ainsi de suite.
Chaque thread doit simplement interroger la file d'attente et l'imprimer.
Une fois que tous les threads sont utilisés dans le pool de threads, commencez par le début du pool.