comment passer des données de thread en cours d'exécution
Lors de l'utilisation de pthread, je peux passer des données au fil de sa création.
Quelle est la bonne façon de transmettre de nouvelles données à un thread en cours d'exécution?
Je suis envisage de faire une variable globale et de faire mon thread de lecture.
Grâce
Encore une fois, des gens essayent de fermer des questions parce qu'ils sont des questions de débutant. N'essayez de vous rappeler vous avez été une fois un débutant vous-même.
OriginalL'auteur monkeyking | 2011-05-30
Vous devez vous connecter pour publier un commentaire.
Qui va certainement travailler. Fondamentalement, les threads sont juste des processus légers qui partagent le même espace mémoire. Les variables globales, dans cet espace de mémoire, sont disponibles pour chaque thread.
Le truc n'est pas avec les lecteurs, pour autant que les écrivains. Si vous avez un simple morceau de mémoire globale, comme un
int
, puis à attribuer à cetteint
sera probablement sûr. Bt envisager quelque chose d'un peu plus compliqué, comme unstruct
. Juste pour être précis, disons que nous avonsMaintenant
s1,s2
sont des variables de typestruct S
. Nous pouvons initialiseret nous pouvons les classer
Mais quand nous leur en attribuer le processeur n'est pas garanti pour terminer le travail à l'ensemble de la structure en une seule étape -- nous dire que c'est pas atomique. Donc, nous allons maintenant, imaginez deux fils:
Nous pouvons voir que nous nous attendons à ce
s2
pour avoir les valeurs{42, 3.14}, {43, 6.28}, {44, 9.42}
....Mais ce que nous voyons imprimé pourrait être quelque chose comme
ou
et ainsi de suite. Le problème, c'est que le thread 1 peut obtenir de contrôle et de "regarder" s2 à tout moment au cours de cette mission.
La morale est que, bien que la mémoire globale est parfaitement possible de le faire, vous avez besoin de prendre en compte la possibilité que votre fils va traverser l'un de l'autre. Il y a plusieurs solutions à ce problème, avec la première d'entre elles étant d'utiliser sémaphores. Un sémaphore a deux opérations, prêter à confusion du nom de néerlandais comme P et V.
P attend tout simplement jusqu'à ce qu'une variable est 0 et le passe, ajouter 1 à la variable; V soustrait 1 de la variable. La seule chose de spécial, c'est qu'ils le font atomiquement -- ils ne peuvent pas être interrompu.
Maintenant, ne vous code
et vous avez la garantie que vous n'aurez jamais le thread 2 demi-réalisation d'une cession tandis que le thread 1 est en train d'imprimer.
(Pthreads a sémaphores, par la manière.)
C'est également à tort, à la fois historiquement et factuellement. Les processus sont des espaces de mémoire avec un-ou avec des threads, plus d'un -- compteur de programme. Un thread est un "thread de contrôle", qui comprend un compteur de programme, et une pile. Voir par exemple l'article de Wiki sur les threads. en.wikipedia.org/wiki/Thread_(computer_science) les Gens obtiennent ce confus pour l'instant, mais une bonne exploitation des systèmes livre sera de discuter de l'histoire et clair.
L'idée que "les discussions sont tout simplement processus légers qui partagent le même espace mémoire" est vraiment un horrible malentendu découlant de l'original unusably mauvais, non-conforme à POSIX mise en œuvre de "threads POSIX" sur Linux, connu comme LinuxThreads. C'est complètement contradictoire à la norme de définition/l'utilisation des mots "processus" et "le fil".
Il est vrai que l'on peut "travailler", mais je pense que vous devriez avoir fait plus pour diriger @monkeyking loin de variables globales. Ce n'est pas propre et il n'a pas d'échelle, pour ne pas mentionner serait un gros WTF pour toute compétente programmeur C. L'extra
void*
que le thread Api de création de vous donner vise exactement à adopter ce type de contexte, de sorte idiomatiques code serait de l'utiliser pour cela.allez lire un des systèmes d'exploitation du livre et de revenir vers moi. @asveikau il me semblait que la question sous-jacente a été de ne pas comprendre le concept entier; si vous préférez de l'expliquer d'une autre façon, je pense que les réponses sont toujours acceptées.
OriginalL'auteur Charlie Martin
J'ai été en utilisant le passage de message, producteur-consommateur dans une file d'attente, les communications mécanisme, tel que suggéré par asveikau, pendant des décennies sans aucun problèmes spécifiquement liés à multiThreading. Il y a certains avantages:
1) Le "threadCommsClass les instances passé dans la file d'attente peuvent souvent contenir tout le nécessaire pour le thread pour faire son travail - membre/s pour les données d'entrée, le membre/s pour la sortie de données, les méthodes pour le fil à appeler pour faire le travail, quelque part, de mettre toute erreur/messages d'exception et un" returnToSender(ce) de l'événement d'appeler pour tout remettre au demandeur par certains thread-safe signifie que le thread n'a pas besoin de savoir. Le travailleur thread s'exécute de façon asynchrone sur un ensemble de données encapsulées qui ne nécessite pas de verrouillage. 'returnToSender(ce) pourrait file d'attente de l'objet sur un autre P-C file d'attente, il pourrait PostMessage à un thread GUI, il peut libérer l'objet d'une piscine ou tout simplement dispose (). Quoi que l'on fasse, le thread n'a pas besoin de le savoir.
2) Il n'est pas nécessaire pour le requérant thread pour savoir quelque chose au sujet de thread qui a fait le travail pour tous le demandeur a besoin est une file d'attente pour s'y appuyer. Dans un cas extrême, le thread de travail à l'autre bout de la file d'attente peut sérialiser les données et de les communiquer à un autre ordinateur sur un réseau, en n'appelant returnToSender(ce) lorsqu'un réseau de réception d'une réponse - le demandeur n'a pas besoin de connaître ce détail - seulement que le travail a été fait.
3), Il est généralement possible d'organiser le "threadCommsClass' les instances et les files d'attente à survivre à la fois le demandeur fil et le thread de travail. Cela facilite grandement ces problèmes lorsque le demandeur ou le travailleur sont terminées et dispose()'d avant les autres - parce qu'ils partagent pas de données directement, il ne peut y avoir aucune AV/whatever. Ce aussi coups de loin tous ces "je ne peux pas arrêter mon travail de fil, car il est collé sur un blocage de l'API" questions - pourquoi la peine de l'arrêter si elle peut être juste orphelins et laissé pour mort, sans possibilité d'écrire sur quelque chose qui est libéré?
4) Un pool de threads réduit à une seule ligne pour la boucle qui crée plusieurs threads de travail et les transmet la même file d'attente d'entrée.
5) de Verrouillage est limité pour les files d'attente. Le plus mutex, condVars, critique d'articles et d'autres synchro verrous il y a dans une application, plus il est difficile de contrôler tout cela et plus grande est la possibilité d'un blocage intermittent qui est un cauchemar pour le débogage. Avec des messages en file d'attente, (idéalement), seule la classe de file d'attente a des serrures. La file d'attente de la classe doit travailler à 100% avec plusieurs producteurs/consommateurs, mais c'est une classe, pas une application complète de uncooordinated de verrouillage, (yech!).
6) Un threadCommsClass peut être soulevée à tout moment, n'importe où, dans n'importe quel thread et poussé sur une file d'attente. Il n'est même pas nécessaire pour le demandeur le code pour le faire directement, par exemple. un appel à un enregistreur de méthode de classe, 'myLogger.logString("l'Opération s'est terminée avec succès");' pourrait copie de la chaîne dans un comms de l'objet, de la file d'attente jusqu'à la thread qui effectue l'écriture de journal et retour "tout de suite". C'est ensuite à l'enregistreur de données de la classe thread pour gérer les données de log quand il retire - il peut écrire dans un fichier journal, il peut se trouver au bout d'une minute que le fichier est inaccessible en raison d'un problème de réseau. Il peut décider que le fichier est trop gros, l'archive et de lancer un autre. Il peut écrire la chaîne de disque et PostMessage la threadCommsClass exemple sur un thread GUI pour l'affichage dans une fenêtre de terminal, que ce soit. Il n'est pas question pour le journal demandant fil, qui porte, comme le font les autres threads qui ont appelé à l'exploitation, sans impact significatif sur les performances.
7) Si vous avez besoin de tuer d'un thread en attente dans une file d'attente, plutôt que de waiing pour le système d'exploitation pour le tuer sur l'app proche, file d'attente un message en disant qu'il teminate.
Il y a sûrement des inconvénients:
1) de Bousculer les données directement dans le thread membres, de signalisation à courir et attendre la fin est plus facile à comprendre et sera plus rapide, en supposant que le fil ne doit pas être créé à chaque fois.
2) Véritablement opération asynchrone, où le fil est mis en file d'attente un peu de travail et, quelque temps plus tard, il retourne en appelant certaines gestionnaire d'événement qui doit communiquer les résultats, est plus difficile à gérer pour les développeurs utilisé pour single-threaded code et nécessite souvent l'état de la machine type de conception où les données de contexte doit être envoyée dans le threadCommsClass de sorte que les mesures appropriées puissent être prises lorsque les résultats de revenir. Si il y a les rares cas où le demandeur a juste à attendre, il peut envoyer un événement dans le threadCommsClass qui obtient signalé par la returnToSender méthode, mais c'est évidemment plus complexe que de simplement attendre sur le fil de la poignée pour l'achèvement.
Quelle que soit la conception est utilisé, oubliez les simples variables globales que d'autres affiches ont dit. Il y a un cas pour certaines types de fil comms - celui que j'utilise très souvent est un thread-safe pool de threadCommsClass cas, (c'est juste une file d'attente qui obtient pré-rempli avec des objets). N'importe quel thread qui souhaite communiquer pour obtenir un threadCommsClass instance de la piscine, de la charge et de la file d'attente. Lorsque le transfert est terminé, le dernier fil à utiliser il la libère de retour à la piscine. Cette approche empêche de runaway new(), et me permet de contrôler facilement le niveau de la piscine pendant les tests, sans aucun complexe de la mémoire-cadres, (j'ai l'habitude de vider la piscine, une barre d'état de chaque seconde avec un timer). Fuite d'objets (niveau descend), et double-objets publiés, (niveau monte), sont facilement détectés et corrigés.
MultiThreading peut être en sécurité et de livrer évolutive, de haute performance des applications qui sont presque un plaisir pour maintenir/améliorer, (presque:), mais vous avez à licencier le simple globals - de les traiter comme Tequila - rapide et facile élevés pour le moment, mais vous savez juste qu'ils vont souffler votre tête hors de demain.
Bonne chance!
Martin
OriginalL'auteur Martin James
Variables globales sont mauvais pour commencer, et même pire avec le multi-thread de programmation. Au lieu de cela, le créateur du thread doit allouer une sorte de contexte de l'objet qui est passé à
pthread_create
, qui contient tout ce que les tampons, les serrures, les variables de condition, les files d'attente, etc. sont nécessaires pour le transfert d'informations vers et à partir du thread.OriginalL'auteur R..
Vous aurez besoin de construire vous-même. L'approche la plus typique nécessite une certaine coopération de l'autre thread, car il serait un peu bizarre de l'interface pour interrompre un thread en cours d'exécution avec des données et d'exécuter du code sur elle... ce serait aussi avoir le même trickiness que quelque chose comme POSIX ou des signaux Irq, à la fois de qui il est facile de se tirer dans le pied pendant le traitement, si vous n'avez pas soigneusement réfléchi... (exemple Simple: Vous ne pouvez pas appeler
malloc
à l'intérieur d'un gestionnaire de signal, car vous pourriez être interrompu au milieu demalloc
, de sorte que vous peut se bloquer lors de l'accès àmalloc
's structures de données internes qui ne sont que partiellement mis à jour.)L'approche typique est d'avoir votre fil routine de création fondamentalement être une boucle d'événements. Vous pouvez construire une structure de file d'attente et le passer en argument à la création de thread de routine. Ensuite, les autres threads peuvent mettre en file d'attente des choses et le fil de la boucle d'événement de dequeue et traiter les données. Remarque c'est plus propre qu'une variable globale (ou global de la file d'attente), parce qu'il peut l'échelle de plusieurs de ces files d'attente.
Vous aurez besoin d'une synchronisation sur la file d'attente de la structure de données. Des livres entiers pourraient être écrits sur la façon de mettre en place votre structure de file d'attente de synchronisation, mais le plus simple serait d'avoir un verrou et un sémaphore. Lors de la modification de la file d'attente, fils de prendre un verrou. Lors de l'attente pour une chose d'être retiré, la consommation fils d'attente sur un sémaphore qui est incrémenté de enqueuers. C'est aussi une bonne idée de mettre en place un mécanisme pour arrêter le thread consommateur.
OriginalL'auteur asveikau