Files
BUT2FI_2025_R3.05/tp/tp4/README.md
2025-09-23 12:48:51 +02:00

3.7 KiB

Signaux

sources à compléter dans le repertoire src

Ex1

  1. Complétez le programme rebours.c qui compte à rebours seconde après seconde à partir d'un nombre passé en arguments. Sur chaque ligne, rebours affiche son pid et le nombre de secondes restantes.
    [denis@portabledenis SYS-TP1]$ ./rebours 5
     2576552: debut
     2576552: 5
     2576552: 4
     2576552: 3
     2576552: 2
     2576552: 1
     2576552: fin
    
    On utilisera getpid et sleep.

Ex2

Pour calculer le nombre \pi, on utilise la méthode de Monte-Carlo. On tire aléatoirement des couples (x,y) de nombres de [0,1]\times[0,1]. La probabilité qu'il tombe dans le disque de rayon 1 est exactement de \frac{\pi}{4}. On procède à plusieurs tirages pour estimer la probabilité correspondante.

uint64_t shots_in=0,shots=0;
double x,y;

int main(int argc, char **argv)
{
	shots_in = 0;
	shots = 0;
	for (;;){
		x = rand()/(RAND_MAX*1.0);
		y = rand()/(RAND_MAX*1.0);
		shots ++;
		if ((x*x+y*y)<=1){
			shots_in ++;
		}    
	}
	/* la probabilité vaut tirsIn/tirs, 
	   Elle converge lentement vers pi/4*/	
}        

En utilisant les signaux, mettre en place :

  • avec SIGALRM, toutes les 5 secondes, l'affichage de la valeur de pi en cours et le nombre de tirs effectués.
  • avec SIGINT l'arrêt du programme (après la demande d'une confirmation), avec l'affichage du temps écoulé depuis son lancement, quand on fait ctrl+C au terminal.
  • avec SIGQUIT la réinitialisation du calcul avec ctrl+\ depuis le terminal. (faites en sorte que toutes les valeurs restent cohérentes)

Dans chaque handler, les 2 autres signaux seront bloqués.

Ex3

Le but est de protéger un morceau de code (section critique) d'un éventuellement déroutement à cause de la prise en compte d'un signal.

int x=2,y=3;
int swap(int *x,int *y){
	int tmp=*x;
	*x=*y;
	*y=tmp;
}

void sig_handler(int signo){
	switch(signo){
		case SIGQUIT : 
			printf("x=%d y=%d\n",x,y);
			break;
	}
}

int main(int argc,char * argv[]){

	assert(set_signal_handler(SIGQUIT,sig_handler)==0);
	while(1){
		swap(&x,&y);
	}
}
  1. Lancez le programme, et envoyez (depuis le terminal) le signal SIGQUIT souvent. La fonction swap est-elle interrompue ? comment le voyez-vous ?
  2. Ajoutez le code nécessaire pour assurer que swap ne soit jamais interrompue par SIGQUIT.

Pour ceux/celles qui ont tout fait

Ex4

On va simuler un match de ping-pong entre un père et son fils, en utilisant le signal SIGUSR1.

  • Le père commence à jouer.
  • On simule 10 échanges. À chaque coup, le père affiche Ping, le fils Pong. L'envoie de la balle consiste à envoyer le signal SIGUSR1 à son adversaire.

La difficulté consiste à synchroniser correctement les échanges.

Voici un premier code naïf :

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

#define N 10
void sig_hand(int sig) {}

sigset_t saveMask, blockMask;

void player_wait(){
	pause();
}
void child_process()
{
	int x = 0;
	while(x < N)
	{
		player_wait();
		printf("\tPong %d!\n", ++x);
		kill(getppid(), SIGUSR1);
	}
	return ;
}

void parent_process(pid_t pid)
{
	int y = 0;
	while (y < N)
	{
		printf("Ping %d!\n", ++y);
		kill(pid, SIGUSR1);
		player_wait();
	}
	return ;
}

int main(int argc, char* argv[])
{
	//set up signal handler for parent & child
	struct sigaction sa;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sa.sa_handler = sig_hand;

	assert (sigaction(SIGUSR1, &sa, NULL) != -1);

	pid_t pid = fork();

	if (pid == 0)
		child_process();
	else
		parent_process(pid);
	return 0;
}
  1. Expliquez pourquoi ce code n'est pas correct (Faites varier N).
  2. Proposez une solution.