IMC!


Contenuti


Foto

 







Curiosando...
Novita  Novità Link  Link Blog  Blog English  Español 
02 - Sincronizzazione di processi con segnali

 | 

In questo articolo sono presenti tre esempi relativi all'utilizzo di segnali per sincronizzare i processi. Le funzioni sono contenute nella libreria signal.h. Le principali sono:
  1. pause(): il processo che chiama questa funzione rimane in attesa finchè viene ricevuto un segnale che lo termina o che attiva una funzione di analisi dei segnali.
  2. alarm(unsigned int secondi): genera un segnale SIGALRM in secondi secondi.
  3. sleep(unsigned int secondi): sospende il processo per un determinato numero secondi di secondi.
  4. signal(int segnale, sighandler_t azione): esegue una azione (ad esempio la chiamata alla funzione azione) quando il processo riceve segnale. Di fatto, maschera la ricezione di un segnale con una funzione. Deve essere specificato solo il nome della funzione, non è possibile passare parametri.
  5. kill(pid_t PID_processo, int sig): se è specificato solo il primo argomento, manda SIGTERM a un processo con pid PID_processo, terminandolo. Può anche mandare un segnale differente, se viene specificato il secondo argomento.


/*
Questo programma mostra l'uso dei segnali per la comunicazione tra padre
e figlio

Il programma crea un orologio che conta fino a 59 minuti e 59 secondi.
Crea due processi. Il padre si occupa di aggiornare lo schermo con il tempo
corrente. Il figlio conta 10 secondi per volta, e avvisa il padre quando ha
finito, tramite il segnale SIGUSR1.

*/

#include <stdio.h>
#include <signal.h>

int pippo = 1;

int min=0, sec=0;

void stampa()
{
  // Su alcuni sistemi Linux è necessario ri-mascherare il segnale,
  // perchè questo rimane mascherato solo per una volta.
  signal(SIGUSR1, stampa);

  sec += 10; // Notazione compatta. Equivale a sec = sec + 10
  if(sec==60) // Se ci sono 60 sec, li azzera e incrementa i minuti.
  {
    sec = 0;
    min++;
    if(min==60) min=0; //Azzera i minuti se sono massimi
  }
  printf("min: %d sec %d\r", min, sec);
  fflush(stdout); // Forza la scrittura dei dati sullo schermo
  return;
}


int main(void)
{
  int PID;
 
  // maschera il segnale SIGUSR1 con stampa. Quando questo segnale sarà ricevuto,
  // verrà chiamata la funzione stampa
  signal(SIGUSR1, stampa);
 
  // Stampa il contatore per la prima volta (i primi 10 secondi)
  printf("min: %d sec: %d\r", min, sec);
  fflush(stdout);

  if( (PID=fork())==0 )
  { // Figlio
    // Il figlio attende 10 secondi e poi invia un segnale SIGUSR1 al padre.
    while(pippo) // Ciclo infinito
    {
      sleep(10); // Attende 10 secondi
      kill(getppid(), SIGUSR1); // Invia al padre il segnale SIGUSR1
    }
  }
  else
  { // Padre
    // Resta in attesa del segnale SIGUSR1. Quando riceve il segnale, viene
    // chiamata la routine corrisposndente indicata da signal(), cioè stampa.
    // E' cioè il padre che si occpua di aggiornare lo schermo.
    while (pippo) pause();
  }
}
 



/* Questo programma crea due processi.
Il padre crea il figlio. Il figlio conta fino a 10000. Nel frattempo
il padre attende 1 secondo, e poi tenta di uccidere il figlio con
SIGTERM. Tuttavia il figlio ha mascherato tale comando con una azione
nulla (di fatto cioè lo ignora). Il padre allora uccide il figlio
con SIGKILL
*/


#include <stdio.h>
#include <signal.h>

int main()
{
  int PID, i;

  if( (PID=fork()) == 0)
  { // Figlio
    signal(SIGTERM, SIG_IGN); // Maschera il segnale SIGTERM con nulla.
    for(i=0; i<10000; i++) // Conta fino a 10000
    {
      printf("Numero: %d\n", i);
      fflush(stdout); // Stampa a schermo
    }
  }
  else
  { // Padre
    sleep(1);
    kill(PID, SIGTERM); // Invia al figlio il segnale SIGTERM
    printf("\nPid del figlio: %d - Tentativo di ammazzare il figlio fallito.\n", PID);
    kill(PID, SIGKILL); // Invia al figlio il segnale SIGKILL
    printf("Figlio ammazzato con SIGKILL.\n\n");
  }
}
 



/*
Questo programma mostra una interazione complessa tra padre e figli.
La sequenza di eventi è la seguente:
1) Il padre genera tre figli.
2) Il padre invia il segnale SIGURS2 a ciascuno dei figli.
3) Ciascun figlio risponde al segnale del padre con un segnale SIGUSR1
4) Il padre attende la risposta di tutti e tre i figli
5) Il padre uccide tutti e tre i figli con SIGKILL
*/

#include <stdio.h>
#include <signal.h>

void rispondi()
{
  printf("Il figlio 1 ha ricevuto il segnale dal padre %d\n", getppid()); fflush(stdout);
  sleep(2);
  printf("Attesa di 1 secondo terminata\n"); fflush(stdout);
  kill(getppid(), SIGUSR1);
  printf("SIGUSR1 Inviato al padre dal figlio %i.\n", getpid()); fflush(stdout);
}

void pippo()
{
 // Non fa nulla. Serve solamente per mascherare SIGUSR1 con una azione nulla.
}

void ammazza(int PID)
{
  signal(SIGUSR1, pippo); // Ignora il segnale SIGUSR1 inviato dai figli
  sleep(1);
  kill(PID, SIGUSR2); // Invia SIGUSR2 al figlio con PID
  pause(); // Attende la risposta del figlio    
}

int main()
{
int pid_1, pid_2, pid_3;

if((pid_1=fork())==0)
  { // Figlio 1
  signal(SIGUSR2, rispondi); // Quando il figlio 1 riceve il SIGUSR2, risponde al padre
  printf("Sono il figlio 1!\n"); fflush(stdout);
  pause(); // Attesa di SIGUSR2
  //pause(); // Attesa di SIGKILL
  }
else if ((pid_2=fork())==0)
  { // Figlio 2
  signal(SIGUSR2, rispondi); // Quando il figlio 2 riceve il SIGUSR2, risponde al padre
  printf("Sono il figlio 2!\n"); fflush(stdout);
  pause(); // Attesa di SIGUSR2
  printf("Il figlio 1 ha ricevuto il segnale dal padre %d\n", getppid()); fflush(stdout);
  kill(getppid(), SIGUSR1); // Invia SIGUSR1 al padre  
  pause(); // Attesa di SIGKILL
  }
else if ((pid_3=fork())==0)
  { // Figlio 3
  signal(SIGUSR2, rispondi); // Quando il figlio 3 riceve il SIGUSR2, risponde al padre
  printf("Sono il figlio 3!\n"); fflush(stdout);
  pause(); // Attesa di SIGUSR2
  printf("Il figlio 1 ha ricevuto il segnale dal padre %d\n", getppid()); fflush(stdout);
  kill(getppid(), SIGUSR1); // Invia SIGUSR1 al padre  
  pause(); // Attesa di SIGKILL
  }
else
  { // Padre
  // ATTENZIONE: SIG_IGN fa sì che anche pause() ignori il segnale ricevuto.
  // pause() resta quindi sempre in attesa.
  signal(SIGUSR1, pippo); // Ignora il segnale SIGUSR1 inviato dai figli.
  printf("Sono il padre!\n"); fflush(stdout);

  ammazza(pid_1); // Invia SIGUSR2 al figlio 1
  printf("Segnale inviato al figlio 1\n"); fflush(stdout);
  ammazza(pid_2); // Invia SIGUSR2 al figlio 2
  printf("Segnale inviato al figlio 2\n"); fflush(stdout);
  ammazza(pid_3); // Invia SIGUSR2 al figlio 3
  printf("Segnale inviato al figlio 3\n"); fflush(stdout);

  printf("\nRicevuti 3 messaggi dai figli\n\n"); fflush(stdout);

  kill(pid_1, SIGKILL); // Ammazza il figlio 1
  kill(pid_2, SIGKILL); // Ammazza il figlio 2
  kill(pid_3, SIGKILL); // Ammazza il figlio 3
  printf("\nFigli uccisi.\n\n"); fflush(stdout);  
  }
}
 


 | 







Commenti

Nessun commento presente!

Scrivi un commento

Pui scrivere quì sotto un commento all'articolo che hai appena letto. Non sono abilitate smile, immagini e link. La lunghezza massima del commento è 4000 caratteri. La buona educazione è benvenuta, tutti i commenti offensivi saranno cancellati.

Your comment (lascia bianco!):
Utente (max 25 caratteri, obbligatorio)
Sito web (max 255 caratteri, facoltativo)
e-Mail (max 255 caratteri, facoltativa, non sarà pubblicata) Your opinion (lascia bianco!):
Commento (max 4000 caratteri, obbligatorio):





Valid HTML 4.01 Transitional
E-Mail - 27.15 ms

Valid HTML 4.01 Transitional