10
votes

Comment interrompre un fil qui attend sur la fonction RECV?

J'ai un lecteur de socket qui se bloque sur la fonction RECV:

size_t recvLen = recv(sock, buf, 512, 0);


1 commentaires

Utilisez la fermeture via la mise en file d'attente d'un APC sur le thread, qui provoquera le retour de RECV avec une erreur car la prise est fermée


6 Réponses :


-1
votes

errrr ... Effectuez un APC sur le même fil? : -))

Sérieusement, cependant, ce n'est pas clair ce que votre objectif est ici.
Si vous souhaitez simplement mettre fin au fil, utilisez la fonction TerminAtetHread .
Si vous souhaitez interrompre cet appel particulier, vous pouvez fermer la prise.


1 commentaires

Terminer le thread ne doit pas être utilisé car il n'indique pas les DLL et ne laisse pas le fil au nettoyage. La fermeture de la prise est possible, mais vous avez peut-être encore besoin de la prise.



10
votes

Vous pouvez l'interrompre en faisant file d'attendre un APC à celui-ci via weeuUserAPCC . Cependant, il est probablement dangereux de mettre fin au fil de l'APC. Queue Un APC ne termine pas le RECV , il l'interrompt simplement; Une fois que l'APC revient, il revenait à attendre sur recv à nouveau.

Si vous souhaitez arrêter complètement le recv complètement, vous devez utiliser Sélectionner avec un délai d'attente pour attendre que des données soient disponibles. Vous pouvez ensuite vérifier si vous devriez continuer à attendre des données ou de continuer à chaque délai d'attente.


1 commentaires

Appelez Closocket () Dans l'appel APC et il retournera, pas besoin de prise asynchronisation ou d'appels de terminaison diabolique :)



0
votes

Je pense que la meilleure façon de gérer ce problème est de placer la prise en mode d'E / S non bloquant, de sorte que le fil ne bloque jamais à l'intérieur de la Recv (ou en envoi (), à ce sujet). Le fil ne doit jamais bloquer uniquement à l'intérieur de SELECT () (ou WaiTmultiPleObjects ()). De cette façon, l'appel SELECT () (ou WaiTmultiPleObjects ()) reviendra si les données arrivent pour la prise (auquel cas vous pouvez ensuite appeler Recv () pour obtenir les nouvelles données sans blocage), mais vous pouvez également avoir sélectionner () / WaiTmultipleObjects () retourne quand autre chose se passe; par exemple. quand il reçoit une invite du fil principal. Si vous utilisez SELECT (), cette invite peut être le fil principal en envoyant un octet sur une autre paire de prise (avec le fil principal en maintenant une extrémité de la paire de socket et le fil d'E / S tenant l'autre extrémité); Si vous utilisez WettMultiPleObjects (), je pense que vous pouvez utiliser l'une des méthodes d'événement / signalisation Windows standard qui causerait WaiTmultiPleObjects () de retourner.


3 commentaires

Vous n'avez pas besoin de placer la prise en mode non bloquante afin d'utiliser Sélectionner () . Vous pouvez utiliser SELECT () avec des sockets de blocage. Appelez simplement SELECT () Pour vous assurer que la prise est lisible avant d'appeler RECV () , alors `recv () ne bloquera pas même si la prise est en mode blocage.


Je ne sais pas comment cela est plus facile / meilleur que de mettre la prise en mode non bloquante. Maintenant, au lieu d'ajouter une ligne de code, vous devez ajouter une ligne de code avant chaque appel potentiellement bloquant sur la prise (et si vous ou les futurs maintenants de code, oubliez jamais de le faire, vous aurez une subtile et dure. détecter le bogue dans votre programme qui pourrait coûter à quelqu'un beaucoup de temps à suivre)


En outre, l'approche Check-Select-ReCVV () ne fonctionne pas toujours de manière fiable: Stackoverflow.com/a/5352634/ 131930



4
votes

Si vous ne voulez plus recevoir de données, vous pouvez tuer la prise à tout moment. Appelez simplement proches () dessus, la fonction en question renvoie immédiatement une erreur.

Qu'est-ce que j'ai fait dans le passé, il suffit d'exécuter un autre fil avec un délai d'attente, après la période d'attente si un drapeau "Ne meurez pas" n'est pas défini, tuez la prise.


0 commentaires

1
votes

Vérification du tampon de prise avant de RECV est plus flexible plutôt que de couvrir beaucoup pour SELECT () Support, je pense. Vous pouvez appeler ioctlsocket (sockhandle, fionread, longint (comptinebuffer)) pour voir s'il y a des données dans la mémoire tampon réseau à lire, puis appelle Recv (Sockhandle, Buff, Countinbuffer, 0) . De cette façon, vous pouvez faire un seul appel de RECV pour lire l'ensemble du mémoire tampon de lecture réseau si vous allouez suffisamment le buff lui-même avec Countinbuffer. Sinon, vous devez appeler RecV dans une boucle pour lire le tampon réseau, qui est la voie traditionnelle. Dans les deux cas, vous êtes toujours dans les contraintes du comptinebuffer .


0 commentaires

-1
votes

Le seul moyen d'interrompre vraiment un bloc de blocking RECV () Appelez et définissez-le complètement est de fermer la prise d'un autre contexte de fil que celui qui est bloqué. Si ce n'est pas une option, vous devez ré-écrire votre logique de prise. Préférable d'utiliser des E / S non bloquant ou asynchrones, de cette façon RECV () (ou wsaecv () car ce dernier) ne bloquera jamais, et vous pouvez faire ce que vous besoin de faire (comme vérifier les conditions de terminaison de fil) pendant que la lecture est effectuée en arrière-plan.


3 commentaires

Assurez-vous simplement que vous n'avez pas d'affection de course où l'autre thread aurait pu le fermer pour vous déjà, ou vous pouvez fermer un descripteur de socket ouvert pour une autre prise (une nouvelle prise) déjà [?]


Re: ASYNC Apparemment, c'est possible en utilisant WaitformultiPleObjects FFMPEG.ORG/PIPERMAIR/FFMPEG -Devel / 2013-décembre / 152211.html


Vous ne pouvez utiliser aucun des waitfor ... Object (s) Fonctions avec poignées de prise. Vous devriez utiliser des poignées d'événements à partir de CreateEeEvent () à la place, appelant setevent () lorsque la prise de courant complète. Ou utilisez wsacreatsevent () avec wsaeventselect () et wsawaitformultiplex () . Ou utilisez CreateIocompletionPort () avec getQueSueCompletionStatus () .