8
votes

Attendez qu'un fil détaché finit en C ++

Comment puis-je attendre qu'un fil détaché ait fini en C ++?

Je m'en fiche d'un statut de sortie, je veux juste savoir si le fil est terminé ou non.

i 'm Essayez de fournir une enveloppe synchrone autour d'un outil de Tirebroyarty asynchrone. Le problème est un accident de la condition de course étrange impliquant un rappel. La progression est:

  1. J'appelle la troisièmepartie et enregistrez-vous un rappel
  2. Lorsque la troisième partie termine, elle m'introduit en utilisant le rappel - dans un fil détaché, je n'ai aucun contrôle réel.
  3. Je veux que le fil de (1) soit attendu jusqu'à ce que (2) soit appelé.

    Je veux envelopper cela dans un mécanisme qui fournit un appel de blocage. Jusqu'à présent, j'ai: xxx

    aussi loin que possible, cela devrait fonctionner, et cela le fait généralement, mais il se bloque parfois. Autant que je puisse déterminer du centre-virgule, je suppose que ceci:

    1. Lorsque le rappel diffuse la fin de M_DONE, le fil d'attente se réveille
    2. Le fil d'attente est maintenant fait ici et attendez est détruit. Tous les membres de l'attente sont détruits, y compris le mutex et le cond.
    3. Le fil de rappel essaie de continuer à partir du point de diffusion, mais utilise maintenant la mémoire qui a été publiée, ce qui entraîne une corruption de mémoire.
    4. Lorsque le fil de rappel tente de revenir (au-dessus du niveau de ma méthode de rappel médiocre), le programme se bloque (généralement avec un SIGSEGV, mais j'ai vu Sigill plusieurs fois).

      J'ai essayé beaucoup de mécanismes différents pour essayer de résoudre ce problème, mais aucun d'entre eux ne résout le problème. Je vois toujours des accidents occasionnels.

      EDIT : Plus de détails:

      Cela fait partie d'une application massivement multithreadée, la création d'une attente statique n'est donc pas pratique. .

      J'ai dirigé un test, créant une attente sur le tas et fuit délibérément la mémoire (c'est-à-dire que les objets d'attente ne sont jamais traités), et cela n'en a entraîné aucun crash. Donc, je suis sûr que c'est un problème d'attente d'être distribué trop tôt.

      J'ai également essayé un test avec un Sleep (5) après le déverrouillage dans attendre , et cela n'a également produit aucun crash. Je déteste compter sur un kludge comme ça.

      EDIT : TIMEPARTY Détails:

      Je ne pensais pas que c'était pertinent au début, mais le Plus j'en pense, plus je pense que c'est le vrai problème:

      Les trucs de troisième partie que j'ai mentionnés et pourquoi je n'ai aucun contrôle sur le fil: Ceci utilise Corba.

      Donc, il est possible que Corba se tienne une référence à mon objet plus longtemps que prévu.


0 commentaires

4 Réponses :


3
votes

Oui, je crois que ce que vous décrivez, c'est ce qui se passe (condition de race sur Deallocate). Un moyen rapide de résoudre ce problème est de créer une instance statique d'attente, qui ne sera pas détruite. Cela fonctionnera aussi longtemps que vous n'avez pas besoin d'avoir plus d'un serveur en même temps.

Vous utiliserez également de manière permanente cette mémoire, elle ne sera pas contraignante. Mais ça ne semble pas trop mal.

Le problème principal est qu'il est difficile de coordonner la durée de vie de vos constructions de communication de fil entre les threads: vous aurez toujours besoin d'au moins une construction de communication de rallonges pour communiquer lorsqu'il est sûr de détruire (au moins dans des langues sans collection de déchets, comme C ++. ).

EDIT : Voir les commentaires pour quelques idées sur refcountating avec un mutex global.


5 commentaires

Malheureusement, c'est dans une application massivement multithreadée, et nous voulons vraiment des objets d'attente séparés pour chacun - sinon cela nous ralentit trop.


De plus, si nous utilisons une attente statique, il y a le problème d'essayer de coordonner quel fil doit reprendre le fil.


Ok, tu peux faire ça. Vous pouvez ajouter un champ Refcount à l'objet d'attente, protégé par un mutex global. Commencez le Refcount à 2, puis avez le rappel et le serveur décrémentez les deux refcount lorsque vous avez terminé. Si le mutex mondial devient votre goulot d'étranglement, il existe d'autres solutions plus compliquées.


De plus, vous n'avez pas besoin du mutex global si vous pouvez utiliser des opérations atomiques pour le réfCount.


Excellent! Le refCounting est en fait fourni par Corba, mais cela a résolu le problème! Merci!



0
votes

Au meilleur de ma connaissance, il n'y a pas de moyen portable de demander directement à un thread si c'est fait en cours d'exécution (c'est-à-dire non pthread _ fonction). Ce que vous faites est la bonne façon de le faire, au moins jusqu'à avoir une condition que vous signalez. Si vous voyez des accidents que vous assurez que vous êtes sûr due à l'objet WAIT est utilisé lorsque le fil qui le crée a quitté (et non quelques autres problème de verrouillage subtil - tout Trop commun), le problème est que vous devez vous assurer que le attendre n'est pas étant distribué, en gérant à partir d'un fil autre que celui qui fait la notification. Mettez-le dans la mémoire globale ou allouez de manière dynamique et partagez-la avec ce fil. Il ne suffit tout simplement pas de ne pas avoir le fil attendu seul la mémoire de l'attente, faites le fil de l'attente.


0 commentaires

0
votes

Est-ce que vous initialisez et détruisez-vous correctement le mutex et la condition Var correctement?

Wait::Wait()
{
    pthread_mutex_init(&m_mutex, NULL);
    pthread_cond_init(&m_cond, NULL);
    m_done = false;
}

Wait::~Wait()
{
    assert(m_done);
    pthread_mutex_destroy(&m_mutex);
    pthread_cond_destroy(&m_cond);
}


1 commentaires

Oui, le mutex etond sont initialisés / détruits correctement. J'utilise en fait des cours d'emballage sur ceux qui ont été bien testés. Et oui, je suis certain que l'attente est détruite prématurément - tandis qu'un fil est toujours à attendre :: rappel.



0
votes

Si votre hypothèse est correcte, le module tiers semble être buggy et vous devez proposer une sorte de hack pour faire fonctionner votre candidature.

statique attendre n'est pas réalisable. Que diriez-vous de attendre piscine (elle peut même augmenter à la demande)? Votre application utilise-t-elle la piscine de thread pour exécuter? Bien qu'il y ait toujours une chance que le même attendre soit réutilisé tandis que le module tiers l'utilise toujours. Mais vous pouvez minimiser ces chances en traitant correctement les attentes vacantes dans votre piscine.

Disclaimer: Je ne suis en aucun cas un expert en sécurité du fil, alors considérez ce post comme une suggestion d'un profane.


0 commentaires