2013-04-16 13 views
5

Mam ten kod i muszę wielokrotnie blokować program, czekając na sygnał. Mój nauczyciel chce, żebyśmy używali sigsuspend i masek zamiast wstrzymywać lub spać. Nie jestem zaznajomiony z sigsuspendą lub maską, wiem że sigsuspend() tymczasowo zastępuje maskę sygnału procesu wywołującego maską podaną przez maskę, a następnie zawiesza proces aż do dostarczenia sygnału, którego akcja ma wywołać obsługę sygnału lub zakończyć proces. Ale jak mogę to zaimplementować.Jak używać sigsuspend

#include <stdlib.h> 
#include <signal.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <sys/types.h> 

unsigned Conta = 0; 

void mypause(int sign) 
{ 
    switch (sign) 
    { 
     case SIGINT: 
      printf("You've pressed ctrl-C\n"); 
      printf("I'm running waiting for a signal...\n"); 
      Conta++; 
      break; 

     case SIGQUIT: 
      printf("You've pressd ctrl-\\n"); 
      printf("Number of times you've pressed CTRL-C: %d", Conta); 
      exit(0); 
      break; 
    } 
} 

int main() 
{ 
    alarm(3); 
    printf("I'm Alive\n"); 

    signal(SIGINT, mypause); 
    signal(SIGQUIT, mypause); 
    printf("I'm running, waiting for a signal...\n"); 
    while (1) 
    { 
    } 

    return (0); 
} 
+0

Ukrywasz SIGINT i SIGQUIT, a następnie wywołujesz sigpause z maską, która pozwala na ponowne odczytanie tych dwóch sygnałów. Kiedy sigpause wraca, sygnały są ponownie maskowane. Pozwala to na bezpieczne sprawdzanie zmiennych statycznych. –

Odpowiedz

8

Prostym sposobem na rozpoczęcie jest po prostu wywołanie sigsuspend z pustą maską (tj.Każdy sygnał może obudzić program):

sigset_t myset; 
(void) sigemptyset(&myset); 
while (1) { 
    (void) printf("I'm running, waiting for a signal...\n"); 
    (void) sigsuspend(&myset); 
} 

Następnym krokiem byłoby wykorzystanie sigprocmask wyłączyć swoje dwie obsługiwane sygnały (SIGINT i SIGQUIT) występowaniu innych niż gdy czekasz z nimi w sigsuspend. Wtedy używałbyś "starej maski" otrzymanej od sigprocmask zamiast pustej maski podczas zawieszania.

6

Opis GNU libc manual wydaje się jasne i dokładne:

Funkcja: int sigsuspend (const sigset_t * set)

Funkcja ta zastępuje maskę sygnałów procesu za pomocą zestawu, a następnie zawiesza proces dopóki nie zostanie dostarczony sygnał, którego działanie to albo zakończyć proces, albo wywołać funkcję obsługi sygnału. Innymi słowy, program jest skutecznie zawieszany, dopóki nie nadejdzie jeden z sygnałów , który nie jest członkiem zestawu.

Jeśli proces zostanie obudzony przez dostarczenie sygnału, który wywołuje funkcję obsługi, i funkcja obsługi zwraca, a następnie sigsuspend również zwraca.

Maska pozostaje ustawiona tylko tak długo, jak długo czeka sigsuspend. Funkcja sigsuspend zawsze przywraca poprzednią maskę sygnału, gdy zwraca ona wartość .

Warunki powrotu i błędy są takie same jak w przypadku pauzy.

Z sigsuspend można wymienić pauzę lub pętlę uśpienia w poprzedniej części z czymś całkowicie niezawodne:

sigset_t mask, oldmask; 

... 

/* Set up the mask of signals to temporarily block. */ 
sigemptyset (&mask); 
sigaddset (&mask, SIGUSR1); 

... 

/* Wait for a signal to arrive. */ 
sigprocmask (SIG_BLOCK, &mask, &oldmask); 
while (!usr_interrupt) 
    sigsuspend (&oldmask); 
sigprocmask (SIG_UNBLOCK, &mask, NULL); 

Ten ostatni kawałek kodu jest trochę trudne. Kluczowym punktem do zapamiętania jest to, że gdy sigsuspend powraca, resetuje sygnał procesu o masce do pierwotnej wartości, wartość sprzed wywołania sigsuspend - w tym przypadku sygnał SIGUSR1 jest ponownie blokowany. Drugie wywołanie do sigprocask'a jest konieczne, aby jawnie odblokować ten sygnał .

Jeszcze jedna uwaga: możesz się zastanawiać, dlaczego pętla while jest konieczna, , ponieważ program najwyraźniej czeka tylko na jeden sygnał SIGUSR1 . Odpowiedź jest taka, że ​​maska ​​przekazana do sigsuspend pozwala na obudzenie procesu dostarczania innych rodzajów sygnałów, na przykład sygnałów sterowania zadaniami. Jeśli proces zostanie obudzony przez sygnał , który nie ustawi usr_interrupt, po prostu zawiesza się ponownie , aż "właściwy" rodzaj sygnału ostatecznie nadejdzie.

Ta technika wymaga kilku linii przygotowania, ale jest to potrzebne tylko raz dla każdego rodzaju kryterium oczekiwania, którego chcesz użyć. Kod, który faktycznie czeka, to tylko cztery linie.