Sind std::signal und std::raise Thread-sicher?

Lesezeit: 6 Minuten

Benutzeravatar von xmllmx
xmllmx

Die C- und C++-Standards unterstützen das Signalkonzept. Der C11-Standard besagt jedoch, dass die Funktion signal() in Multithread-Umgebungen nicht aufgerufen werden kann oder das Verhalten undefiniert ist. Aber ich denke, der Signalmechanismus ist von Natur aus für Multithread-Umgebungen.

Ein Zitat aus dem C11-Standard 7.14.1.1.7

“Die Verwendung dieser Funktion in einem Multithread-Programm führt zu undefiniertem Verhalten. Die Implementierung soll sich so verhalten, als ob keine Bibliotheksfunktion die Signalfunktion aufruft.”

Irgendwelche Erklärungen dazu?

Der folgende Code ist selbsterklärend.

#include <thread>
#include <csignal>

using namespace std;

void SignalHandler(int)
{
    // Which thread context here?
}

void f()
{
    //
    // Running in another thread context.
    //
    raise(SIGINT); // Is this call safe?
}

int main()
{
    //
    // Register the signal handler in main thread context.
    //
    signal(SIGINT, SignalHandler);

    thread(f).join();
}

  • Die Signalisierung war ursprünglich für die Interprozesskommunikation (IPC) vorgesehen. In POSIX war die Signalunterstützung in Multithread-Apps meist ein nachträglicher Einfall, und viele Threading-Sachen werden in Gegenwart von asynchronen Signalen wirklich böse.

    – nneonneo

    30. Januar 2013 um 20:47 Uhr

  • Das muss nicht sein, wie die Norm sagt.

    – David Schwartz

    30. Januar 2013 um 20:49 Uhr

  • Außerdem, warum sollte man das wirklich brauchen? Sie haben viel einfachere Möglichkeiten, innerhalb einer Multithread-App zu kommunizieren, als sich selbst zu signalisieren.

    – Millielch

    30. Januar 2013 um 20:55 Uhr


  • Es ist Standard, ich mag standardmäßig bereitgestellte Funktionen, wenn überhaupt, besser als vom System bereitgestellte.

    – xmllmx

    30. Januar 2013 um 20:58 Uhr


  • @A.Mikhaylov Ist das nicht so exakt Was sagt das Standardzitat in der Frage des OP? Undefiniertes Verhalten bedeutet, dass Sie beispielsweise nicht wissen, ob ein Signal-Handler unterbricht alle die Threads, oder ob es auf dem ausgeführt wird zur Zeit Ausführungsthread oder auf einem vorhersehbaren Thread wie demjenigen, der den Handler festgelegt hat. Wenn letzteres der Fall ist, wird dies den anderen Threads zuvorkommen oder warten, bis er an der Reihe ist? Dies ist nur die Spitze des Eisbergs, wenn es um Dinge geht, die Sie beachten müssen Erweitern Sie das definierte Verhalten dieser Funktionen für Multithreading. Der C++-Standard hat gerade entschieden, es gar nicht erst zu versuchen.

    – Millielch

    23. Juli 2013 um 14:24 Uhr

Aber ich denke, der Signalmechanismus ist von Natur aus für Multithread-Umgebungen.

Ich denke, dieser Satz ist das zentrale Missverständnis. signal() ist eine Methode zur Inter-Prozess Kommunikation, nicht für inter-Faden. Threads teilen sich einen gemeinsamen Speicher und können daher über Mutexe und Kontrollstrukturen kommunizieren. Prozesse haben kein gemeinsames Gedächtnis und müssen mit einigen expliziten Kommunikationsstrukturen auskommen, wie z signal() oder das Dateisystem.

  • Wenn ein Prozess einen Signal-Handler registriert und ein anderer Prozess raise; Kann der Signalhandler des ersten Prozesses das Signal empfangen?

    – xmllmx

    30. Januar 2013 um 21:09 Uhr

  • @xmllmx: Vom Standard nicht definiert. Unter Linux ja. Wenn Sie jedoch etwas Linux-spezifisches tun, verwenden Sie einfach pthread.

    – Thiton

    30. Januar 2013 um 21:11 Uhr

  • Sind diese Funktionen heute veraltet und nutzlos? Unterstützen die Standards sie nur für die Abwärtskompatibilität?

    – xmllmx

    30. Januar 2013 um 21:14 Uhr

  • @xmllmx: signal wird ersetzt durch sigaction, aber die Funktionen an sich sind vollkommen in Ordnung. Sie sind einfach nicht für Multithread-Programme gedacht.

    – Thiton

    30. Januar 2013 um 21:16 Uhr

  • @xmllmx Signale, wie sie in C definiert sind, sind für nichts besonders nützlich. Es erfordert zusätzliche implementierungsdefinierte Garantien, wie z. B. dass bestimmte Bibliotheksfunktionen in einem Handler aufgerufen werden können, um sie nützlich zu machen. Windows unterstützt nicht viel, wenn überhaupt, über das hinaus, was vom Standard gefordert wird. Stattdessen verfügt Windows über eigene plattformspezifische Methoden für die Kommunikation zwischen Prozessen. Für die Kommunikation zwischen Threads wird die C++11-Thread-Bibliothek unter Windows unterstützt, sodass Sie portablen, standardkonformen Code für die Kommunikation zwischen Threads schreiben können.

    – Namen53

    30. Januar 2013 um 21:53 Uhr


Ich denke, Sie verwechseln die prozessspezifische Signalisierung mit der Kommunikation zwischen Threads. Wenn Sie Informationen zwischen Threads austauschen möchten, werden Sie wahrscheinlich im neuen finden, was Sie suchen C++11-Thread-Unterstützungsbibliothek. Es kommt natürlich darauf an, was man wirklich machen möchte.

Soweit ich Ihren Code beurteilen kann, möchten Sie, dass ein Thread ein Ereignis auf irgendeine Weise “signalisiert”, und Sie möchten in der Lage sein, Code auszuführen, wenn dieses Ereignis signalisiert wird. Angesichts dessen würde ich mir den Futures-Abschnitt in der Thread-Unterstützungsbibliothek genauer ansehen.

  • Ich kann Faden, Zukunft, Versprechen usw. verstehen und verwenden. Ich möchte nur wissen, warum, nicht wie.

    – xmllmx

    30. Januar 2013 um 21:55 Uhr

  • Fair genug. Ich denke, ich würde dann fragen, was du mit sicher meinst – Fragst du, ob andere Threads unterbrochen werden? Fragen Sie, ob mehrere Threads in den Signalhandler eintreten können?

    – Carl

    30. Januar 2013 um 22:16 Uhr

  • @xmllmx Warum? Denn das sind die Werkzeuge, die für die Aufgabe vorgesehen sind, Threads zur Zusammenarbeit zu bringen, wenn signal() ist nicht so, wie die Dokumentation Ihnen sagt. Wie in hat sich niemand die Mühe gemacht, nützliche Eigenschaften zu definieren, die es für diese Situation haben würde. (So ​​wird ein Signalhandler auf dem Thread ausgeführt, der ihn definiert hat, oder was auch immer.) Sie fragen, warum Sie keinen Hammer verwenden sollten, um Gemüse zu würfeln. Sicher, wenn Sie darauf hämmern, erhalten Sie am Ende kleinere Gemüsestücke, aber es ist kaum der Ansatz, den Sie wählen möchten.

    – Millielch

    30. Januar 2013 um 23:56 Uhr


  • @millimoose, +1 für deine Erklärungen. Ich denke, das liegt daran, dass unter Windows nur wenige Leute diese Funktionen verwenden.

    – xmllmx

    31. Januar 2013 um 9:09 Uhr

  • @xmllmx MSDN sagt mir auch Unterstützung für <thread>, <mutex>und wahrscheinlich sind alle anderen Header-Dateien, die sich auf diese C++-Funktion beziehen, neu in VS2012, sodass dies auch die Dinge erklären würde.

    – Millielch

    31. Januar 2013 um 13:33 Uhr

Die Aussage des C11-Standards, dass „die Verwendung dieser Funktion in einem Multithread-Programm zu undefiniertem Verhalten führt“, bezieht sich speziell auf die Funktion signal(). Die Frage ist also, ob die Verwendung von signal() erfolgt “in einem Multithread-Programm”.

Soweit ich das beurteilen kann, ist der Begriff „Multithread-Programm“ im C-Standard nicht definiert, aber ich würde damit ein Programm meinen, in dem mehrere Ausführungs-Threads erstellt und noch nicht abgeschlossen wurden. Das würde damals bedeuten signal() in Ihrem Beispielprogramm aufgerufen wird, ist das Programm nicht multithreaded und daher ist das Verhalten des Programms unter dieser Anforderung nicht undefiniert.

(C++11 erfordert jedoch, dass „Alle Signal-Handler eine C-Verknüpfung haben müssen“, [18.10 Other runtime support [support.runtime] S.9]. Da Ihr Beispielprogramm einen Handler mit C++-Verknüpfung verwendet, ist das Verhalten undefiniert.)


Wie andere bereits betont haben, sind Signale nicht für die Kommunikation zwischen Threads gedacht. Zum Beispiel geben die C- und C++-Standards nicht einmal an, auf welchem ​​Thread sie laufen. Die Standardbibliothek bietet stattdessen andere Tools für die Kommunikation zwischen Threads, wie Mutexe, Atomic usw.

Ich glaube, Sie interpretieren den Begriff einfach falsch undefiniertes Verhalten, was leider sehr überladen ist mit der Bedeutung “es werden schlimme Dinge passieren”. Hier bedeutet der Begriff wirklich nur, was er sagt: Der C-Standard macht keine Annahmen darüber, was es bedeutet, zu verwenden signal in einem Multithread-Kontext.

Im Allgemeinen die signal/raise interface im C-Standard ist an sich nicht sehr nützlich, sondern nur ein Platzhalter für plattform-/betriebssystemspezifische Dinge, die darüber definiert werden.

Also für eine Interaktion zwischen signal und Drohungen geben dir keinen Vertrag. Oder anders ausgedrückt, das Zusammenspiel von signal und Threads bleibt der Plattformimplementierung überlassen.

1432430cookie-checkSind std::signal und std::raise Thread-sicher?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy