Dormir un thread de travail dans un serveur de fichiers

J’implémente un serveur de fichiers et il reçoit les demandes de plusieurs clients. Chaque client envoie plusieurs demandes. Du côté serveur, le thread principal génère un nouveau thread de travail pour gérer les demandes chaque fois qu’un nouveau client se connecte. Un thread de travail gère toutes les demandes du client pour lequel il a été créé. Ainsi, une fois que le thread a traité une requête, il attend d’être réveillé par le thread principal lorsqu’une autre requête du même client arrive.

Je ne sais pas comment implémenter la dernière ligne. C’est comment puis-je mettre un fil en veille et le réactiver?

Merci

Vous ne “mettez pas un fil en sumil”. Un thread va dormir lorsqu’il lance un appel système bloquant.

Il existe de nombreuses façons d’implémenter ce que vous décrivez, le plus courant étant peut-être le “modèle de pool de threads” . Cela est généralement implémenté à l’aide d’une queue sécurisée pour les threads, qui peut à son tour être implémentée avec des mutex et des variables de condition.

Le thread de travail s’endormit lorsqu’il attend la variable de condition (pthread_cond_wait) et le maître le réveille en signalant la variable de condition (pthread_cond_signal).

Une petite recherche devrait permettre de trouver un certain nombre d’exemples de code basé sur pthread pour les files d’attente.

Les threads de gestion de vos clients ont-ils un état quelconque pour le client? Si oui, je peux comprendre pourquoi vous auriez besoin d’un seul thread dédié à chaque client. Si tel est le cas, vous pouvez utiliser une queue producteur-consommateur pour chaque thread de gestionnaire de client, comme suggéré par Cnicutar et d’autres affiches. J’utilise habituellement une combinaison de sémaphores avec un mutex, car une telle synchronisation est disponible sur toutes les plateformes, mais les condvars sont corrects. La manière dont vous identifiez le client lorsqu’une demande de fichier arrive n’est pas claire. Par conséquent, la gestion des threads du client peut être délicate ou non. Quand une demande de fichier arrive dans le thread principal, comment savoir quelle queue utiliser?

Rgds, Martin

Vous devriez étudier le problème des producteurs-consommateurs. En un mot, vous voulez faire quelque chose comme ceci:

  • Le thread de travail essaie d’ obtenir le “travail” d’une queue
  • Si la queue est vide, le thread se bloque (variable de sémaphore / condition), sinon il récupère le travail et le traite.
  • La queue principale place les travaux en queue et informe les travailleurs (“hé, il y a du travail à faire”)
  • Un travailleur averti se réveille instantanément et tente d’ obtenir un travail de la queue.

L’astuce consiste à le faire très élégant:

  • le get devrait automatiquement bloquer lorsque la queue est vide
  • le put devrait automatiquement signaler les travailleurs qui l’attendent

Comment feriez-vous cela avec ce que Linux met à votre disposition?

  • sempahores
  • variables de condition pthreads

Revenons maintenant à votre question. Il semble légèrement douteux que vous lanciez un fil pour chaque client. Ce serait beaucoup plus simple si vous pouviez disposer d’un pool de threads traitant les demandes de n’importe quel client.

J’ai résolu le problème par des threads créés au début d’une connexion client, puis le thread reçoit et envoie des messages directement au client plutôt qu’au thread principal qui reçoit et envoie les messages après que les threads de travail ont effectué la tâche.

Vous avez plusieurs possibilités, mais j’ai implémenté une solution multithread similaire, comme suit:

  • Autoriser la méthode de votre thread de travail à renvoyer quand il n’a pas de travail à faire
  • Lorsque votre thread parent reçoit une demande, ajoutez-la à la queue du thread de travail et appelez une méthode “Wakeup”, comme suit:

     private void Wakeup() { if (!_workerThread.IsBusy) _workerThread.RunWorkerAsync(); } 

Cela vous permettra de ne pas suspendre votre thread en état de veille, ce qui nécessiterait de vérifier régulièrement si un réveil a été demandé. Cela met la responsabilité de réveiller le thread de travail sur le thread parent.