Die kurze Antwort auf Ihre Frage ist ja.Sie arbeiten, obwohl der Prozess, an den sie sich anschliessen, mit Berechnungen oder Wartezeiten beschäftigt ist. Die einzige Einschränkung ist, dass der Prozess sich nicht ändert und mit SIGALRM
selbst spielt, was Probleme verursachen würde. Wenn ein Signal ankommt, wird die normale Ausführung eines Prozesses/Threads unterbrochen und der Signal-Handler aufgerufen. Das ist die ganze Idee der Signalverarbeitung und warum sie asynchronous
heißt.
Die längere Antwort auf Ihre Frage ist nein. Sie möchten den Fortschrittsbericht nicht über den Signal-Handler-Mechanismus implementieren, da die API, die Sie in einem Signal-Handler verwenden können, sehr begrenzt ist. Um genau zu sein das Beispiel, das Sie falsch bezeichnet haben, da es fprintf(3)
verwendet. Wie in einer der Antworten angegeben, sind die Signale asynchron. Dies bedeutet, dass, wenn das Signal in der Mitte des Hauptcodes anruft, beispielsweise malloc(3)
, und Ihr Code malloc(3)
ebenfalls anruft (Sie können nie wissen, printf(3)
kann malloc(3)
für Pufferung und andere Bedürfnisse anrufen), dann werden Sie mallocs eigene interne Daten korrumpieren Strukturen und verursachen das Programm zu Fehler. Möglicherweise haben Sie sogar Probleme, Ihre eigenen Funktionen aufzurufen, die nicht asynchron sicher sind. Sie haben eine Liste sicherer Funktionen, die Sie in einem Signal-Handler aufrufen können. Sie finden diese unter man 7 signal
unter Async-signal-safe functions
. Also ja, technisch können Sie Fortschrittsberichterstattung über alarm(3)
implementieren, solange Sie bereit sind, mit dieser reduzierten API zu leben, und das ist der Grund, warum ich es nicht tun würde, wenn das Programm single threaded by design ist und es keine Möglichkeit gibt Ich sehe den Fortschrittsberichtscode als zukünftigen Erweiterungen unterworfen, die es schwer machen, innerhalb eines Signalhandlers zu schreiben.
Ein weiteres Problem, das zu Ihrem Beispiel angegeben wurde, ist, dass alarm(2)
keine Subsekunden-Argumente akzeptiert und das obige Beispiel sollte die Kompilierung nicht vollständig bestanden haben oder zumindest einige Warnungen über diese Tatsache angezeigt haben.
Für die Mikrosekundenauflösung können Sie setitimer(2)
mit ITIMER_REAL
wie angegeben verwenden.
Für Nanosekunde Auflösung auf Linux können Sie timer_create(2)
verwenden, CLOCK_REALTIME
, SIGEV_SIGNAL
und timer_settime(2)
dass viele weitere Funktionen.
Hier ist ein Beispielcode. Beachten Sie, dass dies eigene Fehlerbehandlungsmakros verwendet. Sie können demos-linux
#include <signal.h> // for signal(2), SIG_ERR
#include <unistd.h> // for alarm(2), write(2)
#include <stdlib.h> // for EXIT_SUCCESS
#include <err_utils.h> // for CHECK_NOT_M1(), CHECK_NOT_SIGT()
#include <stdio.h> // for snprintf(3), STDERR_FILENO
/*
* This is an example of doing progress reports via the SIGALRM signal every second.
* The main code does a tight calculation loop and the progress reporting to stderr
* (file descriptor 2) is done via the alarm signal handler.
*/
/*
* The variables are global to allow the signal handler to access them easily
* You DONT need to initialize them to 0 since that is the default.
* The 'volatile' on i is *critical* since it will be accessed asynchronously
* and the compiler needs to know not to put it in a register since that
* will mean that we cannot report it's value correctly from the signal
* handler.
*/
volatile unsigned long i;
/*
* Remember that this is a signal handler and calls to fprintf(3) or the like
* are forbidden so we are forced to use async-safe function (see man 7 signal).
* That is the reason for the cumbersome code. Hopefully snprintf(3) is safe enough
* to use.
*/
static void handler(int sig) {
// we have to reschedule the SIGALRM every time since the alarm(2)
// is a one time deal.
CHECK_NOT_SIGT(signal(SIGALRM, handler), SIG_ERR);
// no error code from alarm(2)
alarm(1);
char buf[100];
int len=snprintf(buf, sizeof(buf), "did [%ld] units of work...\n", i);
CHECK_NOT_M1(write(STDERR_FILENO, buf, len));
}
int main(int argc, char** argv, char** envp) {
CHECK_NOT_SIGT(signal(SIGALRM, handler), SIG_ERR);
// no error code from alarm(2)
alarm(1);
// a very long calculation
while(true) {
/* Do some real work here */
i++;
}
return EXIT_SUCCESS;
}
in diesem Projekt in einem übersetzbar Zustand sehen Wie kann ich es 500ms machen akzeptieren, zum Beispiel? –
Verwenden Sie 'setitimer' mit dem' ITIMER_REAL'. Suchen Sie anhand dieser Funktion nach Beispielen. – nategoose