2009-03-18 10 views

Antwort

10

Ein Thread wird es bekommen, und es gibt keine Möglichkeit zu sagen, welche.

Dies scheint nicht ein vernünftiges Design. Gibt es einen Grund, warum Sie zwei Threads benötigen, die recv() auf der gleichen Buchse aufrufen?

+0

Nein, ich implementiere das selbst für ein Projekt und ich wollte wissen, was passieren sollte – Claudiu

+0

Ich fragte, weil ich keinen guten Grund sehe, es so zu gestalten. Einer der Vorteile von Threading besteht darin, Dinge wie Sockets zu isolieren, um die Handhabung zu vereinfachen. Sharing liest auf einem Socket zwischen Threads führt stattdessen viel Komplexität. – dwc

+8

Das Lesen von zwei Threads aus demselben Socket ist sinnvoll, wenn es sich um einen UDP-Socket für ein verbindungsloses Protokoll wie DNS handelt. Jeder Thread arbeitet dann unabhängig von eingehenden Anfragen. – bdonlan

3

Socket-Implementierungen sollten Thread-sicher sein, so dass genau ein Thread die Daten erhalten sollte, sobald sie verfügbar sind. Der andere Anruf sollte nur blockieren.

3

ich eine Referenz für diese nicht finden können, aber hier ist mein Verständnis:

eine Garantie des Herstellers von Thread-Sicherheit ihre eigenen Sockets verwenden jeder sicher, dass mehrere Threads können nur bedeuten kann; Es garantiert nicht Atomizität über einen einzelnen Aufruf, und es verspricht keine bestimmte Zuordnung der Daten des Sockets unter mehreren Threads.

Angenommen, Thread A ruft recv() an einem Socket auf, der TCP-Daten empfängt, die mit hoher Rate übertragen werden. Wenn recv() ein atomarer Aufruf sein muss, kann Thread A alle anderen Threads daran hindern, ausgeführt zu werden, da er fortlaufend ausgeführt werden muss, um alle Daten einzuziehen (bis sein Puffer sowieso voll ist). Das wäre nicht gut. Daher würde ich nicht annehmen, dass recv() immun gegen Kontextwechsel ist.

Umgekehrt, Thread A macht einen Aufruf Aufruf von recv() auf einem TCP-Socket, und die Daten kommen langsam herein. Daher kehrt der Aufruf von recv() mit errno auf EAGAIN zurück.

In beiden Fällen annimmt Thread B recv() auf dem gleichen Socket, während Thread A noch Daten empfängt. Wann hört Thread A auf, Daten an ihn zu übergeben, damit Thread B Daten empfangen kann? Ich kenne keine Unix-Implementierung, die versuchen wird sich zu erinnern, dass Thread A mitten in einer Operation am Socket war; stattdessen ist es Sache der Anwendung (Threads A und B), über ihre Verwendung zu verhandeln.

Im Allgemeinen ist es am besten, die App so zu gestalten, dass nur einer der Threads recv() auf einem einzelnen Socket aufruft.

+0

Ich denke, dass Sie hier mit Ihren Annahmen falsch liegen. recv() ruft ein Datenpaket ab und wird normalerweise mit UDP verwendet, mit TCP erhält es immer noch ein Datenpaket, aber wenn Sie auf der Senderseite nicht sehr vorsichtig waren, können Sie den Inhalt von zwei Schreibvorgängen in einem recv erhalten. –

+0

Okay, ich habe nur die Dokumente überprüft und es ist ein bisschen komplizierter als ein Paket, abhängig von Flags, aber das ist, was ich als den üblichen Fall in Linux-Apps beobachtet habe, an denen ich gearbeitet habe. –

+0

UDP-Datagramme sind sicherlich sicherer als TCP-Streams in Threads. Ich bin mir nicht sicher, ob sie 100% thread-sicher sind - wenn du ein EINTR bekommst (geht das immer noch?), Dann kehrt Thread A vorzeitig von recv() zurück und gibt Thread B die Chance, hineinzuspringen. –

2

Vom man page auf recv

A recv() auf einem Sockel SOCK_STREAM kehrt so viel verfügbaren Informationen wie die Größe des mitgelieferten Puffer kann halten.

Nehmen wir an, Sie verwenden TCP, da es in der Frage nicht angegeben wurde. Angenommen, Sie haben Thread A und Thread B, die beide auf recv() für Socket s blockieren. Sobald s einige Daten empfangen hat, entsperrt es einen der Threads, sagen wir A, und gibt die Daten zurück. Die zurückgegebenen Daten werden für uns von zufälliger Größe sein. Thread A prüft die empfangenen Daten und entscheidet, ob eine vollständige "Nachricht" vorliegt, wobei es sich bei einer Nachricht um ein Konzept auf Anwendungsebene handelt.

Thread A entscheidet, dass er keine vollständige Nachricht hat, daher ruft er recv() erneut auf.Aber in der Zwischenzeit blockierte B bereits auf der gleichen Buchse und hat den Rest der "Nachricht" erhalten, die für Thread A gedacht war.

Jetzt haben beide Thread A und Thread B eine unvollständige Nachricht und werden, je nachdem, wie der Code geschrieben wird, die Daten als ungültig wegwerfen oder seltsame und subtile Fehler verursachen.

Ich wünschte, ich könnte sagen, dass ich das nicht aus Erfahrung wusste.

Also während recv() selbst technisch Thread sicher ist, ist es eine schlechte Idee, zwei Threads gleichzeitig aufrufen, wenn Sie es für TCP verwenden.

Soweit ich weiß, ist es völlig sicher, wenn Sie UDP verwenden.

Ich hoffe, das hilft.

Verwandte Themen