2009-12-06 5 views
6

Ich verwende asio synchrone Sockets, um Daten über TCP aus einem Hintergrund-Thread zu lesen. Dies ist in einer "Server" -Klasse gekapselt.Interrupt boost :: asio synchronen Lese?

Allerdings möchte ich den Thread beenden, wenn der Destruktor dieser Klasse aufgerufen wird. Das Problem ist, dass ein Aufruf einer der Lesefunktionen blockiert, so dass der Thread nicht einfach beendet werden kann. In Win32 gibt es eine API dafür: WaitForMultipleObjects die genau das machen würde, was ich will.

Wie würde ich einen ähnlichen Effekt mit Boost erreichen?

Antwort

2

In unserer Anwendung stellen wir die "beendende" Bedingung ein und verwenden dann eine Eigenverbindung zu dem Port, den der Thread überwacht, so dass er aufwacht, die Beendigungsbedingung notiert und beendet.

Sie könnten auch die Boost-Implementierung überprüfen - wenn sie nur einen einfachen Lesevorgang auf dem Socket machen (dh nicht wie WaitForMultipleObjects selbst intern verwenden), dann können Sie wahrscheinlich feststellen, dass es nichts gibt, einfach und sauber zu entsperren der Faden. Wenn sie auf mehrere Objekte warten (oder auf einen Completion-Port), können Sie nachsehen, ob die Möglichkeit, blockenden Thread zu wecken, nach außen ausgesetzt ist.

Schließlich könnten Sie den Thread töten - aber Sie müssen außerhalb Boost gehen, um dies zu tun, und die Konsequenzen, wie baumelnde oder durchgelaufene Ressourcen zu verstehen. Wenn Sie herunterfahren, ist das möglicherweise kein Problem, je nachdem, was der Thread sonst noch gemacht hat.

2

Ich habe keinen einfachen Weg gefunden, dies zu tun. Angeblich gibt es Möglichkeiten, Win32 IOCP abzubrechen, aber es funktioniert nicht gut unter Windows XP. MS hat es für Windows Vista und 7 repariert. Die empfohlene Vorgehensweise zum Abbrechen von Asio async_read oder async_write ist das Schließen des Sockets.

  • [destructor] beachten Sie, dass wir für die Fertigstellung Handler Teardown wollen warten, bis die Buchse [destructor]
  • schließen
  • [destructor]

  • [Abschluss], wenn Sie nach unten reißen und wir gerade gescheitert Da der Socket geschlossen wurde, benachrichtige den Destruktor, dass die Completion-Handler fertig sind.

  • [Abschluss] sofort zurückkehren.

Seien Sie vorsichtig, wenn Sie dies implementieren möchten. Das Schließen der Steckdose ist ziemlich einfach. "Warte auf Komplettierungshandler" ist jedoch ein großes Unterprogramm. Es gibt mehrere subtile Fälle und Rassenbedingungen, die auftreten können, wenn der Thread des Servers und sein Destruktor interagieren.

Das war subtil genug, dass wir einen Abschluss Wrapper (ähnlich io_service::strand nur zu handhaben synchron Cancelling alle anstehenden Abschluss Rückrufe.

1

Der beste Weg zu schaffen, ist eine socketpair(), bauen (was auch immer das in boost::asio parlance ist), fügen Der Leser endet mit der Ereignisschleife und schließt dann das Ende des Brenners. Sie werden sofort mit einem eof-Ereignis an diesem Socket geweckt.

Der Thread muss sich dann freiwillig selbst abschalten.

Die spawner des Gewindes sollte in seinem destructor, haben die folgenden:

~object() 
{ 
    shutdown_queue.shutdown(); // ask thread to shut down 
    thread.join();    // wait until it does 
} 
-1

Verwendung socket.cancel(); Beenden aller aktuellen asynchronen Vorgänge, die auf einem Socket blockieren. Client-Sockets müssen möglicherweise in einer Schleife beendet werden. Ich musste den Server nie auf diese Weise schließen, aber Sie können shared_from_this() verwenden und cancel()/close() in einer Schleife ausführen, ähnlich wie das Boost-Chat-Beispiel async_writes an alle Clients.