Urmatorul program invoca functiile specifice unui semafor de mai multe ori. Un parametru optional specifica daca se doreste crearea sau distrugerea semaforului. Vom folosi doua caractere diferite pentru a indica intrarea respectiv iesirea dintr-o regiune critica. Programul, invocat cu un parametru afiseaza caracterul X, iar cel fara parametru afiseaza caracterul 0. Deoarece un singur proces poate intra intr-o regiune critica la un anumit moment de timp, toate caracterele X si 0 vor aparea in pereche.
/* * semun.h - definitie pentru union semun */ #ifndef _SEMUN_H #define _SEMUN_H 1 union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */ struct seminfo *__buf; /* buffer pentru IPC_INFO (Linux specific) */ }; #endif /* * fisier de test pentru lucrul cu semafoare */ #define _POSIX_SOURCE 1 #define _SVID_SOURCE 1 #define _XOPEN_SOURCE 1 #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include "semun.h" static int set_semvalue (void); static void del_semvalue (void); static int semaphore_p (void); static int semaphore_v (void); static int sem_id; int main(int argc, char *argv[]) { int i; int pause_time; char op_char = 'O'; srand ((unsigned int) getpid ()); sem_id = semget ((key_t) 1234, 1, 0666 | IPC_CREAT); if (argc > 1) { if (!set_semvalue ()) { fprintf (stderr, "Failed to initialize semaphore\n"); exit (EXIT_FAILURE); } op_char = 'X'; sleep (2); } /* * bucla infinita in care intram si parasim regiunea critica de 10 ori; * in prima faza vom pune procesul sa astepte, folosind operatia P * asupra semaforului */ for(i = 0; i < 10; i++) { if (!semaphore_p ()) exit (EXIT_FAILURE); printf ("%c", op_char); fflush (stdout); pause_time = rand () % 3; sleep (pause_time); printf ("%c", op_char); fflush (stdout); /* * la iesirea din regiunea critica apelam semaphore_v */ if (!semaphore_v ()) exit (EXIT_FAILURE); pause_time = rand () % 2; sleep (pause_time); } printf("\n%d - finished\n", getpid ()); if (argc > 1) { sleep (10); del_semvalue (); } return 0; } /* * apelul set_semvalue initializeaza un semafor folosind comanda SETVAL * in cadrul unui apel SEMCTL */ static int set_semvalue(void) { union semun sem_union; sem_union.val = 1; if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0); return(1); } /* * functia del_semvalue are o forma asemanatoare cu cea de mai sus, * mai putin faptul ca apelul semctl utilizeaza comanda IPC_RMID pentru * a elimina id-ul semaforului */ static void del_semvalue(void) { union semun sem_union; if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1) fprintf(stderr, "Failed to delete semaphore\n"); } /* * semphore_p schimba valoarea semaforului cu -1 (eventual asteapta) */ static int semaphore_p(void) { struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1; /* P() */ sem_b.sem_flg = SEM_UNDO; if (semop(sem_id, &sem_b, 1) == -1) { fprintf(stderr, "semaphore_p failed\n"); return(0); } return(1); } /* * semaphore_v incrementeaza valoarea semaforului cu 1, astfel ca * semaforul devine disponibil */ static int semaphore_v(void) { struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; /* V() */ sem_b.sem_flg = SEM_UNDO; if (semop(sem_id, &sem_b, 1) == -1) { fprintf(stderr, "semaphore_v failed\n"); return(0); } return(1); }
Rularea executabilului generat de fisierul de mai sus rezulta in urmatorul output:
razvan@ragnarok:~/cfiles/solab/labs/lab5$ gcc -Wall -pedantic -ansi -o sem semaphore.c razvan@ragnarok:~/cfiles/solab/labs/lab5$ ./sem 1 & [3] 4247 razvan@ragnarok:~/cfiles/solab/labs/lab5$ XXXXXXX./sem XOOOOXXXXOOXXOOXXOOXXOOXX 4247 - finished OOOOOOOO 4258 - finished razvan@ragnarok:~/cfiles/solab/labs/lab5$