Wie auf signal select() sofort zurückkehrt?
Habe ich einen worker-thread, der hört auf einem TCP-socket für eingehende Datenverkehr und die Pufferung der empfangenen Daten für den Haupt-thread zugreifen (nennen wir diese Buchse Eine). Aber der worker-thread hat auch zu tun einige regelmäßige Operationen (sagen wir, einmal pro Sekunde), auch wenn keine Daten ankommen. Daher verwende ich select()
mit einem timeout, so dass ich nicht brauchen, zu halten polling. (Beachten Sie, dass der Aufruf receive()
auf einem nicht blockierenden socket, und dann schlafen Sie für eine Sekunde ist nicht gut: die eingehenden Daten sollten sofort verfügbar sein für den Haupt-thread, auch wenn der Haupt-thread könnte nicht immer in der Lage sein, um es zu verarbeiten richtigen Weg, daher die Notwendigkeit der Pufferung.)
Nun, ich muss auch in der Lage sein, um ein signal worker-thread zu tun einige andere Sachen sofort; aus dem Haupt-thread, die ich brauche, um den worker-thread - select()
Gegenzug sofort. Jetzt habe ich das folgendermaßen gelöst (Ansatz im wesentlichen übernommen aus hier und hier):
Bei Programm-Start der worker-thread erstellt zu diesem Zweck eine zusätzliche Steckdose des Datagramms (UDP) Typ aus, und bindet es zu einem zufälligen port (nennen wir diese Buchse B). Ebenso der main-thread erzeugt ein datagram-socket für das senden. In dem Aufruf select()
wird der thread jetzt führt die beiden Eine und B in der fd_set
. Wenn der Haupt-thread braucht, um zu signalisieren, es sendto()
's ein paar bytes an den entsprechenden port auf localhost
. Zurück in der worker-thread, wenn B bleibt in der fd_set
nach select()
gibt, dann recvfrom()
genannt wird und die empfangenen bytes werden einfach ignoriert.
Diese scheint sehr gut zu funktionieren, aber ich kann nicht sagen, wie ich die Lösung, vor allem, da es erfordert die Bindung eines zusätzlichen port für Bund auch, weil es fügt einige zusätzliche socket-API-Aufrufe, die fehlschlagen, Schätze ich, und ich habe nicht wirklich Lust, herauszufinden, die entsprechende Aktion für jeden der Fälle.
Ich denke, im Idealfall würde ich gerne eine Funktion, die Eine als Eingabe, und tut nichts, außer macht select()
Gegenzug sofort. Allerdings weiß ich nicht so eine Funktion. (Ich denke, ich könnte zum Beispiel shutdown()
die Buchse, aber die Nebenwirkungen sind nicht wirklich akzeptabel 🙂
Ist dies nicht möglich, ist die zweitbeste option wäre die Schaffung eines B das ist viel dummier als einer realen UDP-socket, und nicht wirklich erfordern die Zuteilung von beschränkten Ressourcen (über einen angemessenen Betrag von Speicher). Ich denke, Unix-domain-sockets würde genau das tun, aber: die Lösung sollte nicht viel weniger sein, cross-Plattform, als das, was ich derzeit habe, obwohl einige mäßige Menge von #ifdef
Zeug ist gut. (Ich bin targeting hauptsächlich für Windows und Linux – und das schreiben von C++ übrigens.)
Bitte nicht schlagen refactoring, um loszuwerden, die zwei separate threads. Dieses design ist notwendig, da der Haupt-thread kann blockiert werden, für längere Zeiträume (z.B., wenn Sie einige intensive Rechen – und ich kann nicht starten regelmäßig aufrufen receive()
aus der innersten Schleife der Berechnung), und in der Zwischenzeit muss jemand buffer für die eingehenden Daten (und aus Gründen, über was ich kontrollieren kann, es kann nicht der Absender).
Jetzt, wo ich dies Schreibe, erkannte ich, dass jemand definitiv beantworten Sie einfach "Boost.Asio", so hatte ich gerade meinen ersten Blick auf Sie... Konnte nicht finden, dass eine offensichtliche Lösung, aber. Beachten Sie bitte, daß ich auch nicht (leicht) beeinflussen, wie socket Eine ist erstellt, aber ich sollte in der Lage sein zu lassen, andere Gegenstände wickeln Sie es, wenn nötig.
InformationsquelleAutor der Frage Reunanen | 2008-12-21
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sind Sie fast da. Verwenden Sie eine "selbst-Leitung" trick. Öffnen Sie ein Rohr, fügen Sie es zu Ihrem
select()
Lesen und schreibenfd_set
schreiben vom Haupt-thread wieder zu entsperren, ein worker-thread. Es ist portabel auf POSIX-Systemen.Habe ich eine Variante gesehen, ähnliche Technik für Windows in einem system (in der Tat verwendet, zusammen mit der oben genannten Methode, getrennt durch
#ifdef WIN32
). Die Entsperrung kann erreicht werden durch hinzufügen eines dummy (ungebundenen) datagram-socket zufd_set
und dann schließen. Der Nachteil ist, dass, natürlich, Sie haben, öffnen Sie es erneut jedes mal.Jedoch in dem oben erwähnten system, das sowohl von diesen Methoden sind eher sparsam, und für unerwartete Ereignisse (z.B. Signale, termination requests). Bevorzugte Methode ist immer noch eine variable timeout auf
select()
je nachdem, wie schnell so etwas geplant ist ein worker-thread.InformationsquelleAutor der Antwort Alex B
Mithilfe einer pipe anstatt sockel ist ein bisschen sauberer, da es keine Möglichkeit gibt, einen anderen Prozess zu fassen zu bekommen und Durcheinander zu bringen.
Über einen UDP-socket definitiv schafft das Potenzial für verirrte Pakete zu kommen und stören.
Eine anonyme pipe wird nie verfügbar sein für alle anderen Verfahren (es sei denn, Sie geben es zu).
Können Sie auch Signale, aber in einem Multithread-Programm werden Sie wollen, stellen Sie sicher, dass alle threads, außer für die, die Sie wollen haben, dass signal maskiert.
InformationsquelleAutor der Antwort MarkR
Unter unix es wird einfach mit einem Rohr. Wenn Sie windows und wollen mit Hilfe der select-Anweisung, damit Ihr code kompatibel mit unix, der trick erstellen Sie ein ungebundenes UDP-socket und schließen funktioniert gut und einfach. Aber Sie haben, um es multi-Thread-sichere.
Die einzige Möglichkeit, die ich gefunden, um diese multi-Thread-sichere schließen und neu der sockel in dem gleichen Gewinde wie die select-Anweisung ausgeführt wird. Das ist natürlich schwierig, wenn der thread blockierend auf die wählen Sie. Und dann kommt in der windows-Aufruf QueueUserAPC. Wenn windows blockiert in der select-Anweisung, die der thread verarbeiten kann, Asynchrone Prozeduraufrufe. Sie können planen, diese von einem anderen thread mithilfe der QueueUserAPC. Windows unterbricht die wählen, führt Ihre Funktion im selben thread, und setzt sich mit der select-Anweisung. Sie können jetzt in Ihre APC-Methode, schließen Sie die Steckdose und erstellen Sie es neu. Garantiert thread-safe und du wirst nie verlieren ein signal.
InformationsquelleAutor der Antwort guido4096