Sémaphore et processus

Bonjour,

Actuellement je tente de comprendre les IPC de type sémaphore en codant un programme qui crée 20 processus, chaque processus correspond à une personne qui veut rentrer dans un ascenseur de manière synchronisé de façon à ce qu’il n’y ait qu’une personne dans l’ascenseur à la fois. Dès qu’un processus est rentré dans l’ascenseur (la zone critique du sem) il se termine.

[code]#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

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

int i;
int N = 20;
pid_t tab[N];

key_t cle;
int semid;
int val[1]={1};

struct sembuf p, v;

cle = ftok(argv[0],0);
semid = semget(cle,1,IPC_CREAT|0666);

semctl(semid,0,SETVAL,val);

p.sem_num = 0;
p.sem_op = -1;
p.sem_flg = 0;

v.sem_num = 0;
v.sem_op =  1;
v.sem_flg = 0;

for(i=0; i<N; i++) {

	tab[i] = fork();

	if(tab[i] == 0) {
		semop(semid, &p, 1);
		printf("Je suis le fils %d et je rentre dans l'ascenseur",getpid());
		semop(semid, &v, 1);
		return EXIT_SUCCESS;
	} else {
		sleep(2);
		semctl(semid, 0, IPC_RMID, 0);
		return EXIT_SUCCESS;
	}
}

}[/code]

Je suis sous Debian amd64 et ce programme n’affiche rien. Est ce que quelqu’un pourrait m’éclairer ?

Merci d’avance !

Ben si il affiche

francois@totoche:/tmp$ ./sem francois@totoche:/tmp$ Je suis le fils 9344 et je rentre dans l'ascenseur francois@totoche:/tmp$ Une remarque ta boucle n’est effectuée qu’une fois ((x2 pour le fork()) à cause du return.

[code]#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

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

int i;
int N = 20;
pid_t tab[N];

key_t cle;
int semid;
int val[1]={1};

struct sembuf p, v;

cle = ftok(argv[0],0);
semid = semget(cle,1,IPC_CREAT|0666);

semctl(semid,0,SETVAL,val);

p.sem_num = 0;
p.sem_op = -1;
p.sem_flg = 0;

v.sem_num = 0;
v.sem_op = 1;
v.sem_flg = 0;

for(i=0; i<N; i++) {

  tab[i] = fork();

  if(tab[i] == 0) {
     semop(semid, &p, 1);
     printf("Je suis le fils %d et je rentre dans l'ascenseur\n",getpid());
     semop(semid, &v, 1);
  } else {
printf("Hou hou %d\n",getpid());
     sleep(2);
     semctl(semid, 0, IPC_RMID, 0);
  }

}
return EXIT_SUCCESS;

}
[/code]correspond peut être à ce que tu veux faire…

[code]#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

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

int i,pr;
int N = 3;
pid_t tab[N];

key_t cle;
int semid;
int val[1]={1};

struct sembuf p, v;

cle = ftok(argv[0],0);
semid = semget(cle,1,IPC_CREAT|0666);

semctl(semid,0,SETVAL,val);

p.sem_num = 0;
p.sem_op = -1;
p.sem_flg = 0;

v.sem_num = 0;
v.sem_op = 1;
v.sem_flg = 0;

for(i=0; i<N; i++) {
pr = getpid();
tab[i] = fork();

  if(tab[i] == 0) {
     semop(semid, &p, 1);
     printf("Je suis le fils %d de %d %d et je rentre dans l'ascenseur\n",i,pr,getpid());
     semop(semid, &v, 1);
  } else {
     sleep(2);
     semctl(semid, 0, IPC_RMID, 0);
  }

}
return EXIT_SUCCESS;

}
[/code]t’aidera à comprendre pourquoi tu as plein de lignes affichées. (Exercice: combien de lignes :slightly_smiling:)

Le deuxième argument de ftok (int proj_id) doit être non nul (cf. man ftok(3))
Il faut aussi tester le code de retour pour voir si il y a eu une erreur (cle == -1)

Le deuxième argument de ftok (int proj_id) doit être non nul (cf. man ftok(3))
Il faut aussi tester le code de retour pour voir si il y a eu une erreur (cle == -1)[/quote]
Tu es sûr de toi pour le id non nul?? Je ne trouve nulle part ça. http://www.linux-kheops.com/doc/man/manfr/man-html-0.9/man3/ftok.3.html par exemple…

Il faut aussi tester le retour de semget (je sais, les codes tester les codes de retour partour c’est chiant, mais on est content d’avoir codé proprement quand ça marche pas et qu’il faut trouver l’erreur)
Et personnelement, j’aurais restreint les droits au maximum (je pense que c’est une bonne habitude)

Merci de vos réponses !

Je ne savais pas pour le second argument du ftok, là en l’occurrence ce n’est pas cela qui pose problème. L’IPC est bien crée (vérifié avec la commande ipcs) - je ne mets pas le de vérification pour ne pas alourdir mon code sur le forum.

En fait, je ne comprends pas pourquoi je ne peux pas mettre de return (quid du exit ?) dans la condition if. Dans un if classique je comprends pourquoi mais dans ce cas là il s’agit d’une condition if de gestion de processus et donc le return devrait être exécuté à la fin de chaque processus fils non ? Parce que là du coup je ne sais pas comment terminer chaque processus fils dès qu’il a eu le sémaphore …

Hum j’ai la page de man sous les yeux :

DESCRIPTION
       La  fonction  ftok() utilise l'identité du fichier indiqué par pathname (qui doit exister et être accessible), et les huit bits de poids faible de
       proj_id (qui doit être non nul) pour créer une clé IPC System V de type key_t, utilisable avec msgget(2), semget(2) ou shmget(2).

Pareil pour la version anglaise.

[quote=“dagost”]Merci de vos réponses !

Je ne savais pas pour le second argument du ftok, là en l’occurrence ce n’est pas cela qui pose problème. L’IPC est bien crée (vérifié avec la commande ipcs) - je ne mets pas le de vérification pour ne pas alourdir mon code sur le forum.

En fait, je ne comprends pas pourquoi je ne peux pas mettre de return (quid du exit ?) dans la condition if. Dans un if classique je comprends pourquoi mais dans ce cas là il s’agit d’une condition if de gestion de processus et donc le return devrait être exécuté à la fin de chaque processus fils non ? Parce que là du coup je ne sais pas comment terminer chaque processus fils dès qu’il a eu le sémaphore …[/quote]

Tu peux mettre un return au fils,
mais pas au père il doit finir sa boucle.

Effectivement je comprends bien mon erreur maintenant :smt003

Pour les droits je vais passer à 0600 tant qu’à faire.

Merci beaucoup

int val[1]={1}; semctl(semid,0,SETVAL,val);

Là aussi ça va pas, mais plus pour un point de vue esthétique,
pour faire les choses propres je te proposes

ou alors pour pousser le bouchon

#ifdef _SEM_SEMUN_UNDEFINED union semun { int val; // <= value for SETVAL struct semid_ds *buf; // <= buffer for IPC_STAT & IPC_SET unsigned short int *array; // <= array for GETALL & SETALL struct seminfo *__buf; // <= buffer for IPC_INFO } val = {.val = 1}; #endif

Mais bon tout ça c’est juste pour dire que je comprenais pas pourquoi tu avais un tableau à une case :wink:

On m’a apprit comme ça (très mal) donc je continue à le faire :frowning:

Heu ya des problèmes de fond aussi…
on ne voit rien si le père lance un fils toutes les 2 secondes,
et que le fils se termine quasiment instantanément.

Il faut que se soit le fils qui prenne du temps,
et le père doit attendre que ses fils soient terminés avant de détruire le sémaphore.

Et pour le pointeur pour val,
je suis pas du tout d’accord,
le man dit :

int semctl(int semid, int semnum, int cmd, ...); La fonction a trois ou quatre arguments, selon la valeur de cmd. Quand il y en a quatre, le quatrième est de type union semun. union semun { int val; /* Valeur pour SETVAL */ struct semid_ds *buf; /* Tampon pour IPC_STAT, IPC_SET */ unsigned short *array; /* Tableau pour GETALL, SETALL */ struct seminfo *__buf; /* Tampon pour IPC_INFO (spécifique à Linux) */ };
Donc pointeur pour buf, array et __buf, mais pas pour val.
De toute manière, ça te sautera aux yeux quand ton programme de test marchera,
tu auras une valeur de val abhérente puisqu’il utilisera l’adresse plutot que la valeur de ton int.

Oui oui j’ai édité, j’ai pris un seg fault en fait.

Par contre pour le ftok, j’ai fouillé un peu
et impossible de trouver une explication pour l’argument non nul.

Par contre, je tiens à préciser que la manière dont ftok est implémenté
ne garantit absolument pas d’avoir une clé unique,
la fonction se contente de prendre quelques bit de l’inode, du périphérique du fichier
et 1 octet sur l’entier passé et de renvoyer ça avec des décalages de bit…

Si quelqu’un a l’explication, je suis preneur :wink: