Szukaj…
Składnia
- niepodpisany alarm (niepodpisane sekundy);
- int kill (pid_t pid, int sig);
Parametry
| Funkcja, parametry, zwracana wartość | Opis | 
|---|---|
| alarm() | nazwa funkcji | 
| unsigned seconds | Sekundy, aby podnieść alarm lub 0, aby anulować dowolny alarm w toku | 
| > = 0 | 0, jeśli żaden inny alarm nie był w toku, w przeciwnym razie liczba sekund, przez które alarm w toku nadal był otwarty. Ta funkcja nie zawiedzie. | 
| - | - | 
| kill() | nazwa funkcji | 
| pid_t pid | . | 
| int sig | 0 lub identyfikator sygnału | 
| 0, -1 | W przypadku powodzenia zwracane jest 0, -1 w przypadku niepowodzenia z ustawieniem errnonaEINVAL,EPERMlubESRCH. | 
Podnoszenie SIGALARM z domyślną akcją
 Za pomocą alarm użytkownik może zaplanować SIGALARM sygnału SIGALARM po określonym czasie. W przypadku, gdy użytkownik nie zablokował, zignorował lub nie określił jawnej procedury obsługi sygnału dla tego sygnału, domyślne działanie dla tego sygnału zostanie wykonane po przybyciu. Zgodnie ze specyfikacją domyślną czynnością dla SIGALARM jest zakończenie procesu: 
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char** argv)
{
    printf("Hello!\n");
    // Set the alarm for five second
    alarm(5); // Per POSIX, this cannot fail
    // Now sleep for 15 seconds
    for (int i = 1; i <= 15; i++)
    {
        printf("%d\n", i);
        sleep(1);
    }
    // And print the message before successful exit
    printf("Goodbye!\n");
    return EXIT_SUCCESS;
}
To daje:
Hello!
1
2
3
4
5
[2]    35086 alarm      ./a.out
Ustawianie obsługi sygnału za pomocą sigaction i podnoszenie sygnałów za pomocą raise
 Aby program reagował na określony sygnał, inny niż domyślna akcja, można zainstalować niestandardową procedurę obsługi sygnału za pomocą sigaction . sigaction otrzymuje trzy argumenty - sygnał do działania, wskaźnik do struktury sigaction_t , która, jeśli nie NULL , opisuje nowe zachowanie i wskaźnik do sigaction_t który, jeśli nie NULL zostanie wypełniony starym zachowaniem (aby można je było przywrócić). Podnoszenie sygnałów w tym samym procesie można wykonać metodą raise . Jeśli potrzebna jest większa kontrola (aby wysłać sygnał do innego procesu, można użyć metody kill lub pthread_kill , która akceptuje docelowy identyfikator procesu lub identyfikator wątku). 
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Signals are numbered from 1, signal 0 doesn't exist
volatile sig_atomic_t last_received_signal = 0;
// Signal handler, will set the global variable
// to indicate what is the last signal received.
// There should be as less work as possible inside
// signal handler routine, and one must take care only
// to call reentrant functions (in case of signal arriving
// while program is already executing same function)
void signal_catcher(int signo, siginfo_t *info, void *context)
{
    last_received_signal = info->si_signo;
}
int main (int argc, char** argv)
{
    // Setup a signal handler for SIGUSR1 and SIGUSR2
    struct sigaction act;
    memset(&act, 0, sizeof act);
    // sigact structure holding old configuration
    // (will be filled by sigaction):
    struct sigaction old_1;
    memset(&old_1, 0, sizeof old_1);
    struct sigaction old_2;
    memset(&old_2, 0, sizeof old_2);
    act.sa_sigaction = signal_catcher;
    // When passing sa_sigaction, SA_SIGINFO flag
    // must be specified. Otherwise, function pointed
    // by act.sa_handler will be invoked
    act.sa_flags = SA_SIGINFO;
    if (0 != sigaction(SIGUSR1, &act, &old_1))
    {
        perror("sigaction () failed installing SIGUSR1 handler");
        return EXIT_FAILURE;
    }
    if (0 != sigaction(SIGUSR2, &act, &old_2))
    {
        perror("sigaction() failed installing SIGUSR2 handler");
        return EXIT_FAILURE;
    }
    // Main body of "work" during which two signals
    // will be raised, after 5 and 10 seconds, and which
    // will print last received signal
    for (int i = 1; i <= 15; i++)
    {
        if (i == 5)
        {
            if (0 != raise(SIGUSR1))
            {
                perror("Can't raise SIGUSR1");
                return EXIT_FAILURE;
            }
        }
        if (i == 10)
        {
            if (0 != raise(SIGUSR2))
            {
                perror("Can't raise SIGUSR2");
                return EXIT_FAILURE;
            }
        }
        printf("Tick #%d, last caught signal: %d\n",
            i, last_received_signal);
        sleep(1);
    }
    // Restore old signal handlers
    if (0 != sigaction(SIGUSR1, &old_1, NULL))
    {
        perror("sigaction() failed restoring SIGUSR1 handler");
        return EXIT_FAILURE;
    }
    if (0 != sigaction(SIGUSR2, &old_2, NULL))
    {
        perror("sigaction() failed restoring SIGUSR2 handler");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
To daje:
Tick #1, last caught signal: 0
Tick #2, last caught signal: 0
Tick #3, last caught signal: 0
Tick #4, last caught signal: 0
Tick #5, last caught signal: 30
Tick #6, last caught signal: 30
Tick #7, last caught signal: 30
Tick #8, last caught signal: 30
Tick #9, last caught signal: 30
Tick #10, last caught signal: 31
Tick #11, last caught signal: 31
Tick #12, last caught signal: 31
Tick #13, last caught signal: 31
Tick #14, last caught signal: 31
Tick #15, last caught signal: 31
Proces popełniający samobójstwo za pomocą kill ()
 Proces może (próbować) wysłać sygnał do dowolnego innego procesu za pomocą funkcji kill() . 
 Aby to zrobić, proces wysyłania musi znać PID procesu odbierającego. Ponieważ bez wprowadzania rasy proces może być jedynie pewien swojego PID (i PID jego dzieci), najprostszym przykładem do zademonstrowania użycia kill() jest wysłanie przez proces sygnału do siebie. 
 Poniżej przykład procesu inicjującego własne zakończenie przez wysłanie sobie sygnału „zabicia” ( SIGKILL ): 
#define _POSIX_C_SOURCE 1
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
int main (void)
{
  pid_t pid = getpid(); /* Get my iown process ID. */
  kill(pid, SIGKILL); /* Send myself a KILL signal. */
  puts("Signal delivery initiated.");  /* Although not guaranteed, 
                                  practically the program never gets here. */
  pause(); /* Wait to die. */
  puts("This never gets printed.");
}
Wynik:
Killed
(... lub podobne, w zależności od wdrożenia)
Obsługa SIGPIPE generowanego przez write () w sposób bezpieczny dla wątków
 Gdy wywoływana jest funkcja write() dla nazwanego lub nienazwanego gniazda potoku lub strumienia, którego koniec odczytu jest zamknięty, zdarzają się dwie rzeczy: 
-  Sygnał SIGPIPEjest wysyłany do procesu, który wywołałwrite()
-  Sygnał SIGPIPEjest wysyłany do wątku, który wywołałwrite()
-  Błąd EPIPEjest zwracany przezwrite()
 Istnieje kilka sposobów radzenia sobie z SIGPIPE : 
-  W przypadku gniazd SIGPIPEmożna wyłączyć, ustawiając opcje specyficzne dla platformy, takie jakMSG_NOSIGNALw Linuksie iSO_NOSIGPIPEw BSD (działa tylko dlasend, ale nie dlawrite). To nie jest przenośne.
-  W przypadku FIFO (nazwanych potoków) SIGPIPEnie zostanie wygenerowany, jeśli program zapisujący użyjeO_RDWRzamiastO_WRONLY, więc koniec odczytu jest zawsze otwarty. Jednak to również wyłączaEPIPE.
-  Możemy zignorować SIGPIPElub ustawić globalny moduł obsługi. To dobre rozwiązanie, ale nie do przyjęcia, jeśli nie kontrolujesz całej aplikacji (np. Piszesz bibliotekę).
-  W najnowszych wersjach POSIX możemy wykorzystać fakt, że SIGPIPEjest wysyłany do wątku, który wywołałwrite()i obsługuje go przy użyciu techniki synchronicznej obsługi sygnałów.
 Poniższy kod przedstawia bezpieczną dla wątków obsługę SIGPIPE dla POSIX.1-2004 i późniejszych. 
Inspiruje go ten post :
-  Najpierw dodaj SIGPIPEdo maski sygnału bieżącego wątku za pomocąpthread_sigmask().
-  Sprawdź, czy istnieje już SIGPIPEza pomocąsigpending().
-  Wywołanie write(). Jeśli koniec odczytu jest zamknięty,SIGPIPEzostanie dodany do maski sygnałów oczekujących iEPIPEzostanie zwrócony.
-  Jeśli write()zwróciłoEPIPE, aSIGPIPEnie oczekiwał jeszcze przedwrite(), usuń go z maski sygnałów oczekujących za pomocąsigtimedwait().
-  Przywróć oryginalną maskę sygnału za pomocą pthread_sigmask().
Kod źródłowy:
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <sys/signal.h>
ssize_t safe_write(int fd, const void* buf, size_t bufsz)
{
    sigset_t sig_block, sig_restore, sig_pending;
    sigemptyset(&sig_block);
    sigaddset(&sig_block, SIGPIPE);
    /* Block SIGPIPE for this thread.
     *
     * This works since kernel sends SIGPIPE to the thread that called write(),
     * not to the whole process.
     */
    if (pthread_sigmask(SIG_BLOCK, &sig_block, &sig_restore) != 0) {
        return -1;
    }
    /* Check if SIGPIPE is already pending.
     */
    int sigpipe_pending = -1;
    if (sigpending(&sig_pending) != -1) {
        sigpipe_pending = sigismember(&sig_pending, SIGPIPE);
    }
    if (sigpipe_pending == -1) {
        pthread_sigmask(SIG_SETMASK, &sig_restore, NULL);
        return -1;
    }
    ssize_t ret;
    while ((ret = write(fd, buf, bufsz)) == -1) {
        if (errno != EINTR)
            break;
    }
    /* Fetch generated SIGPIPE if write() failed with EPIPE.
     *
     * However, if SIGPIPE was already pending before calling write(), it was
     * also generated and blocked by caller, and caller may expect that it can
     * fetch it later. Since signals are not queued, we don't fetch it in this
     * case.
     */
    if (ret == -1 && errno == EPIPE && sigpipe_pending == 0) {
        struct timespec ts;
        ts.tv_sec = 0;
        ts.tv_nsec = 0;
        int sig;
        while ((sig = sigtimedwait(&sig_block, 0, &ts)) == -1) {
            if (errno != EINTR)
                break;
        }
    }
    pthread_sigmask(SIG_SETMASK, &sig_restore, NULL);
    return ret;
}