Mir ist nicht bewusst, dass POSIX es sogar wagt, dieses Thema zu erwähnen, aber ich habe keine erschöpfende Suche durchgeführt.
Einige kurze Experimente mit einem gcc/nptl-System zeigen, dass, wie ich vermutete und ich denke, dass Sie es auch getan haben, gibt es keinen solchen Schutz in NPTL - die Cancellation-Handler werden tatsächlich aufgerufen, aus dem Signal-Handler-Kontext.
Das folgende Programm (Leider für die hackiness etc) zeigt die folgende Ausgabe:
Signal handler called
Sent cancellation
Cleanup called
In sighandler
... anzeigt, dass:
- die Signalbehandlungsroutine dann
- der andere Thread aufgerufen wurde
pthread_cancel()
- wurde der Abbruchbehandler aufgerufen, ohne dass der Signalhandler
abgeschlossen hat
Hier ist das Programm:
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
pthread_t mainthread;
int in_sighandler = 0;
void
cleanup (void *arg)
{
write(1, "Cleanup called\n", strlen("Cleanup called\n"));
if (in_sighandler) {
write(1, "In sighandler\n", strlen("In sighandler\n"));
} else {
write(1, "Not in sighandler\n", strlen("In sighandler\n"));
}
}
void
sighandler (int sig, siginfo_t *siginfo, void *arg)
{
in_sighandler = 1;
write(1,"Signal handler called\n", strlen("Signal handler called\n")); // write() is a CP
usleep(3000000); // usleep() is a CP; not strictly async-signal-safe but happens to be so in Linux
write(1, "Signal handler exit\n", strlen("Signal handler exit\n"));
in_sighandler = 0;
}
void *
thread (void *arg)
{
sleep(1);
pthread_kill(mainthread, SIGUSR1);
usleep(500000);
pthread_cancel(mainthread);
printf("Sent cancellation\n");
return (NULL);
}
int
main (int argc, char **argv)
{
int rc;
struct sigaction sa;
pthread_t threadid;
mainthread = pthread_self();
// Set up a signal handler to test its cancellation properties
sa.sa_sigaction = &sighandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
rc = sigaction(SIGUSR1, &sa, NULL);
assert(rc == 0);
// Set up a thread to send us signals and cancel us
rc = pthread_create(&threadid, NULL, &thread, NULL);
assert(rc == 0);
// Set up cleanup handlers and loop forever
pthread_cleanup_push(&cleanup, NULL);
while (1) {
sleep(60);
}
pthread_cleanup_pop(0);
return (0);
}
Kurzirgend bessere Antwort in Kürze, ich wahrscheinlich bei Ihnen akzeptieren werde. Soweit ich das beurteilen kann, bedeutet das im Grunde genommen nur, dass Sie die Löschung in einem Programm nicht verwenden können, es sei denn, Ihre Signalhandler deaktivieren die Löschung selbst oder vermeiden es, eine Funktion aufzurufen, die ein Abbruchpunkt sein könnte. Dies wiederum bedeutet unglücklicherweise, dass Bibliothekscode, der Threads verwendet, ohne dass das aufrufende Programm die Aufmerksamkeit/Kooperation hat, überhaupt keine Löschung verwenden kann (weil das aufrufende Programm möglicherweise Signalverarbeitungsroutinen eingerichtet hat); Jede Verwendung könnte zu Rennbedingungen führen, bei denen der Signal-Handler abgebrochen wird. –
Ja, das stimmt - streng genommen kann der Signal-Handler die Löschung jedoch nicht deaktivieren (die pthread-Funktionen sind nicht async-signal-sicher). Die Bibliothek * könnte * alle * Signale in beliebigen Threads blockieren, die sie erzeugt, aber das ist nicht ideal (zumal das Blockieren von SIGRTMIN unter Linux die Löschung deaktiviert ...). Ich habe immer gedacht, dass die Löschung gefährlich ist - Sie können keine Bibliotheksfunktionen aus einem abbrechbaren Thread aufrufen, es sei denn, Sie sind sicher, dass die Bibliothek unter Berücksichtigung von Stornierungen konzipiert wurde (andernfalls könnte sie Ressourcen zuweisen, eine Abbruchfunktion aufrufen und dann nie befreie diese Ressourcen ...) – psmears
Für was es wert ist Ich habe gerade das gleiche Programm auf einer Maschine mit Solaris 10 versucht, mit den gleichen Ergebnissen ... Ich denke, das bedeutet, dass, selbst wenn sich herausstellt, etwas in sein Der Standard, der das sicher macht, ist nutzlos, da die gängigsten Implementierungen es nicht unterstützen: -/ – psmears