Comment être sûr qu’un descripteur de fichier a déjà été fermé?

Avant de voter pour clore, veuillez lire, je sais qu’il y a des questions similaires (:

Voici ma situation – J’ai une application qui est multithreadée. Donc, disons que j’ai 10 threads. Tous lisent à partir du même descripteur de fichier (c’est en fait un socket). Et dans une situation très rare, lorsqu’une erreur critique se produit, le socket doit être shutdown par l’un des threads. Le fait est que n’importe lequel de ces threads peut le faire. Si la fermeture du socket a échoué, _Exit( FAILURE ) est exécuté (je sais que cela ressemble à un problème de conception ou de code, mais ce n’est pas le cas, car cela est dû à un tiers non-opensource) lib, qui a un bogue).

Et voici la situation du problème – il est possible que tous tentent d’ shutdown le socket en même temps. Et on le ferme, mais les autres ne peuvent pas le fermer ( shutdown renvoie -1, le socket étant déjà fermé) et le bad _Exit( FAILURE ) est exécuté et cela gâche tout.

Evidemment, j’ai besoin d’une vérification supplémentaire – si le socket est déjà fermé (il est possible que tous les threads aient échoué à fermer le socket pour une raison quelconque, puis au moins un doit exécuter _Exit , c’est pourquoi vérifier le code de retour n’est pas suffisant) ).

Eh bien, j’ai trouvé cette question et on dirait que c’est exactement ce que j’essaie de faire. Mais je sais que tous les appels système prennent du temps (bien sûr) et que le système d’exploitation dépend de la fermeture exacte du socket.

Et voici la question: comment puis-je faire la différence si un socket est déjà fermé ou s’il ne peut pas être fermé pour une raison quelconque? Est-ce que le fcntl m’assurera que si un thread a fermé le socket en même temps si un autre thread essaie d’ shutdown le socket, il échouera et si je vérifie (avec fcntl ), cela fonctionnera pour moi?

J’ai aussi vu les autres réponses comme: “vous pouvez utiliser select ou poll “, mais ce sont toujours des appels système et je ne sais pas si ce sera le meilleur choix. Je ne sais pas non plus comment les utiliser, mais ce n’est pas grave, je suppose.

Merci!


Je peux aussi vérifier les errno par shutdown , mais que signifie “connecté”? Et quelle est la différence entre “connecté” et “pas un descripteur valide”

 ENOTCONN The specified socket is not connected. 

De plus, ce qui me dérange, c’est que le FD, que j’essaie de fermer, pourrait être invalide, car je le prends de /proc/net/tcp mappé avec proc/PID/fd et je ne sais pas si tous les fichiers seront ressembler à la façon, ils regardent sur mon système d’exploitation (le système d’exploitation sera à coup sûr RHEL4 ou RHEL5, si cela compte)

Doh! C’est sacrément long, mais je ne peux pas l’expliquer plus court.

Je suppose que vous dites qu’il est possible que votre application continue raisonnablement après la fermeture du socket?

Il semble qu’une meilleure approche serait d’avoir un thread de médiateur qui est notifié des demandes de fermeture de socket de l’un des threads de travail, notifie les autres threads que le socket est maintenant mort et prend soin de fermer le socket lui-même. Cela élimine les soucis concernant la raison de l’échec, car tout est géré dans un seul thread.

Chaque fois que vous avez une ressource utilisée par plusieurs threads et qui peut être désallouée par l’un d’entre eux, vous devez protéger tous les access avec des verrous. Sinon, vous aurez des conditions de course dangereuses. J’utiliserais un verrou en lecture-écriture sur l’ int contenant le descripteur de fichier. Tout thread souhaitant utiliser la fd doit conserver un verrou de lecture pendant toute la durée de son utilisation, et tout thread souhaitant modifier la variable fd (par exemple, le close et le remplacer par -1 pour empêcher toute utilisation ultérieure) doit contenir un verrou en écriture.

Fondamentalement, c’est la même chose que l’utilisation de la mémoire allouée dynamicment et free .

Vérifier les errno est de loin la meilleure option. De l’ shutdown(2) je peux voir:

  • EBADF s n’est pas un descripteur valide
  • ENOTCONN Le socket spécifié n’est pas connecté
  • ENOTSOCK s est un fichier, pas un socket.

La façon dont je le vois: EBADF signifie qu’il a déjà été fermé et ENOCONN signifie qu’il n’y a pas de connexion derrière ce descripteur (pas la poignée de main à trois voies et tout ce jazz).

Le meilleur moyen de le savoir: faire un perror(3) après l’appel à l’ shutdown échoue et voir ce qu’il dit.

À votre santé

Avez-vous pensé à protéger la fermeture de la prise avec un mutex? En utilisant l’un de ceux-ci, vous pouvez vous assurer qu’un seul thread tente de fermer le socket. Vous devrez créer des appels système, à savoir pthread_mutex_init lors de l’initialisation et pthread_mutex_trylock avant de fermer le socket. Cependant, ces appels doivent être optimisés pour des retours rapides.

Une autre approche qui évite les appels au système serait d’implémenter un mutex vous-même, de sorte que seul l’un des threads parvienne à fermer le socket. Bien sûr, vous devrez adapter l’un des algorithmes existants pour l’exclusion mutuelle afin que les threads ultérieurs n’attendent pas, mais continuent simplement l’exécution.

La réponse correcte était par R .. qui traitait des problèmes de threading. Répondre à la question “comment connaître le statut d’une fd?”: fstat()

Par POSIX: Il retournera -1 sur tout problème avec un descripteur de fichier ou un socket. errno sera défini sur EBADF sur un descripteur de fichier ou un socket déjà fermé. La famille d’appels stat est spécifiquement destinée à tester: les fichiers ( stat ), les liens ( lstat ) et les descripteurs de fichiers ( fstat ).

D’autres appels comme close et shutdown renvoient également des erreurs sur des fd déjà fermés. Mais leur but est autre chose, et tester une prise connectée est un effet secondaire.

Publié parce que les autres appels système mentionnés ne sont pas destinés à tester les descripteurs de fichiers. Une partie de la question originale telle que je la lisais.