Disons que je démarre un fil à recevoir sur un port. L'appel de socket bloquera sur RECVFROM. Ensuite, dans un autre fil, je ferme la prise. P>
sous Windows, cela débloquera RECVFROM et mon exécution de thread finira. P>
sur Linux, cela ne débloque pas RECVFROM et, par conséquent, mon thread est assis ne rien faire pour toujours, et l'exécution du fil ne se termine pas. P>
Quelqu'un peut-il m'aider avec ce qui se passe sur Linux? Lorsque la prise est fermée, je veux recvrom pour débloquer p>
Je continue à lire sur l'utilisation de Select (), mais je ne sais pas comment l'utiliser pour mon cas particulier. P>
4 Réponses :
Pas une réponse, mais la page Linux Fermer Man contient la citation intéressante: p>
Il est probablement imprudent de fermer les descripteurs de fichiers pendant qu'ils peuvent être dans Utilisez les appels système dans d'autres threads dans le même processus. Depuis un fichier Descripteur peut être réutilisé, il y a des conditions de race obscur qui peut provoquer des effets secondaires inattendus. P> blockQuote>
C'est pourquoi j'ai dit "d'une manière ou d'une autre dans un autre fil, je ferme la prise ... Ce cas doit être manipulé et je ne veux pas que la possibilité de mon programme suspendue à jamais à cause d'un fil bloqué sur une prise en attente de la Recvrom quand sa fermeture
@ user657178 Ce cas n'a pas besoin d'être manipulé car le code qui est correct sinon ne peut pas éventuellement i> déclencher ce cas.
Voici un croquis d'un moyen simple d'utiliser SELECT () pour faire face à ce problème:
// Note: untested code, may contain typos or bugs static volatile bool _threadGoAway = false; void MyThread(void *) { int fd = (your socket fd); while(1) { struct timeval timeout = {1, 0}; // make select() return once per second fd_set readSet; FD_ZERO(&readSet); FD_SET(fd, &readSet); if (select(fd+1, &readSet, NULL, NULL, &timeout) >= 0) { if (_threadGoAway) { printf("MyThread: main thread wants me to scram, bye bye!\n"); return; } else if (FD_ISSET(fd, &readSet)) { char buf[1024]; int numBytes = recvfrom(fd, buf, sizeof(buf), 0); [...handle the received bytes here...] } } else perror("select"); } } // To be called by the main thread at shutdown time void MakeTheReadThreadGoAway() { _threadGoAway = true; (void) pthread_join(_thread, NULL); // may block for up to one second }
Et je vous rappelle à nouveau que la réponse "acceptée" pour cette question est tout simplement fausse. Chaque UNIX - de l'original BSD et SYS V ENDWARD - a garanti que lire () jamais i> bloquer après avoir sélectionné () indique que le socket est prêt. Et ainsi la spécification POSIX. Si Linux se comporte différemment, c'est un bug de Linux. Vous ne devez pas encourager les gens à polluer leur code avec des ordures pour répondre aux systèmes brisés.
Bonjour Nemo, si vous dites que le bogue de Linux est corrigé maintenant et que ma mise en garde est trompeuse, c'est une chose. Si OTOH, vous dites que le bogue est toujours présent, mais personne ne doit en parler, alors vous ne mettez que les gens à l'échec. Garder les gens ignorants du comportement de Linux (MIS) n'empêchera pas le problème de les mordre, il ne les empêchera que de pouvoir planifier à l'avance pour la manière dont ils veulent faire face à la question.
Un point juste. Je pense qu'il y a une chance non nulle que ce bogue a été corrigé, car de violer le POSIX si flagreux car il n'y a pas de bonnes raisons est stupide et que les développeurs Linux ne sont pas stupides. Je vais essayer de demander à la liste de diffusion de Linux-Kernel. Et je m'excuse si mon ton était trop hostile; J'ai eu une mauvaise journée...
@Nemo Où puis-je trouver cette garantie? Et quelle clause de Posix pensez-vous que cela viole? Cela semble fou pour moi. Cela signifierait, par exemple, qu'un protocole de réseau vous permettrait de "annuler" les données non traités ne peut être pris en charge par POSIX, ce qui ressemble à une réclamation extraordinaire. Ma compréhension est que SELECT code> est censé être neutre de protocole et que vous ne pouvez pas obtenir une garantie qu'un
lue code> ne bloquerait pas sans tenir compte des règles du protocole. Par exemple, pourquoi la mise en oeuvre de l'UDP ne peut-elle pas déposer un datagramme après avoir déclenché un
lire code> Hit depuis
Sélectionnez CODE>? Quelle règle POSIX est violée?
@Nemo Où ce scénario enfreint-il POSIX? 1. Les checksums UDP sont désactivés. 2. Un datagramme avec une somme de contrôle invalide est reçu sur une prise connectée. 3. A Sélectionnez CODE> appel débloque parce qu'un
lu code> n'aurait pas été bloqué. 4. L'application de la liste de contrôle est activée. 5. A
lire code> appelez maintenant des blocs car aucun datagramme avec une somme de contrôle valide n'a été reçu.
@Davidschwartz: Évidemment, si vous faites quelque chose à la prise entre le SELECT CODE> et le
lisez code> (par exemple, activer l'application de la vérification de la vérification ou diable juste un autre appel à
lire code >) Vous pourriez changer de propriété "prêt à lire". Ce dont nous parlons est
SELECT CODE> DISIONNAIRE La prise est prête à lire, puis à lire immédiatement
Lire code> blocage. Aucun Unix n'a jamais permis cela, mais Linux fait ... et il viole clairement POSIX (voir pubs.opengroup.org/onlinepubs/9699919799/fonctions/select.ht ml et rechercher" considéré comme prêt ").
@Nemo Activation ou désactivation de l'UDP Checksum Appliquer est pas i> une opération sur la prise, c'est une opération sur la connexion. Et il n'ya aucun moyen que vous puissiez savoir si quelque chose d'autre a fait quelque chose à la connexion car la connexion est partagée. Donc, quelque chose que vous n'avez pas de contrôle (une opération sur la connexion partagée) peut modifier la propriété de lecture. Et vous êtes mal interprété POSIX. Il ne dis pas qu'une lecture future réelle ne bloquera pas, il dise une lecture hypothétique simultanée / i> ne bloque pas.
@NEMO Ce n'est pas différent d'une fonction "Obtenir de l'espace libre" disant que l'espace libre signifie qu'une écriture ne retournerait pas une erreur "sans espace". Cela ne signifie pas qu'il y a une garantie d'une erreur future réelle ne retournera pas une erreur "sans espace", car la mise en œuvre n'a pas de contrôle complet sur l'espace disque et ne gèle pas le monde pour vous. Même avec une connexion.
appel Vous penseriez que fermeture (chaussette, shut_rdrwr) code> sur la prise, puis attendez que le fil soit quitté. (I.e.
pthread_join code>). p>
fermer () code> débloquerait le
recvfrom () code>, mais il ne fonctionne pas sous Linux. P>
Shut_RD suffit.
Ce n'est pas le cas et ne peut pas être, garanti de débloquer recvfrom code> sur n'importe quel système i>. Il existe une race inhérente qui ne peut être résolue que par la synchronisation dans l'espace utilisateur.
arrêt (socket, shut_rdrwr) a fonctionné parfaitement à Linux .... Merci
Vous demandez l'impossible. Il n'y a tout simplement pas de moyen possible pour le fil qui appelle Peu importe ce que vous faites, il sera toujours possible pour l'appel à Il n'y a aucun moyen pour le fil qui entre code> Recvfrom code> à un signal d'une manière ou d'une autre sur le thread qui appelle Considérez les éléments suivants: P>
oups. P>
Ne jamais faire quelque chose même à distance comme ça. Une ressource ne doit pas être libérée alors qu'un autre fil est, ou pourrait être, l'utiliser. Période. P> Fermer code> pour savoir que l'autre thread est bloqué dans
Recvfrom code>. Essayez d'écrire du code qui garantit que cela se produit, vous constaterez que c'est impossible. P>
Fermer code> pour courir avec l'appel à
RECVFROM code>. L'appel à
Fermer code> Modifie ce que le descripteur de socket fait référence, il peut donc modifier la signification sémantique de l'appel à
Recvrom code>. P>.
Fermer code> qu'il est bloqué (par opposition à être sur le point de bloquer ou juste entrer dans l'appel du système). Donc, il n'ya littéralement aucun moyen possible d'assurer le comportement de
Fermer code> et
Recvrom code> sont prévisibles. P>
Recvfrom code>, mais il est préempté par d'autres choses que le système doit faire. li>
Fermer code>. Li>
Socket CODE> et obtient le même décsriptor que celui que vous
Fermer CODE> D. LI>
recvfrom code>, et maintenant, il reçoit à partir de la prise ouverte de la bibliothèque. LI>
ol>