#include #include #include #include static const char usage[]="%s: potrzebuje dwoch parametrow, nazwy i liczby\n" "nazwa bedzie nazwa semafora, liczba podaje czas w s.\n"; /* Semafory sa uzywane na kolei: jak pociag wjezdza na odcinek toru, * to semafor ustawia sie na "zamkniety", zeby nastepny pociag nie * wjechal na ten sam odcinek, i nie zderzyly sie; kiedy wyjezdza, * semafor przestawia sie na "otwarty", i nastepny pociag moze jechac. * Cos podobnego mozna zrobic dla programow uzywajacych wspolnego zasobu. * * Zasady dzialania semafora o wartosci poczatkowej 1: * * pierwszy proces, ktory wywola sem_czekaj(), zmniejszy semafor do 0 * inne beda czekac, az pierwszy wywola sem_sygnal() * wtedy ktorys proces bedzie mogl sie wykonywac, * a inne beda czekac, az z kolei on wywola sem_sygnal(); * * w rezultacie: tylko jeden proces moze wykonywac czesc * pomiedzy sem_czekaj() i sem_sygnal(); oczywiscie, trzeba * pilnowac, zeby po kazdym sem_czekaj() wysolac sem_sygnal() * kiedy juz mozna pozwolic innym procesom dzialac dalej. * * Tutaj semafor nie pozwala innym procesom wypisywac cyfr na * ekran, kiedy jeden proces jest w trakcie wypisywania grupy. * W ten sposob cyfry wychodza grupami, gdy pisze wiele procesow. */ void sem_czekaj(int h) { static struct sembuf s={0,-1,SEM_UNDO}; /* -1 - zmiana */ semop(h,&s,1); /* 0 - numer semafora, 1 - ile */ } void sem_sygnal(int h) { static struct sembuf s={0,1,SEM_UNDO}; /* 1 - zmiana */ semop(h,&s,1); } int sem_ustaw(int h, int v) { union semun { int val; struct semid_ds *buf; unsigned short *array; } u; u.val=v; if((v=semctl(h,0,SETVAL,u))==-1) /* 0 - numer semafora */ perror("ustawianie semafora"); return v; } int sem_usun(int h) { int v; /* usuwanie musi zaczekac, az inni skoncza... */ do { sem_czekaj(h); poll(NULL,0,90); v=semctl(h,0,GETNCNT,0); sem_sygnal(h); poll(NULL,0,10); } while(v>0); printf("koniec\n"); fflush(stdout); if((v=semctl(h,0,IPC_RMID,0))==-1) perror("usuwanie semafora"); return v; } main(int ac, char **av) { /* parametry: nazwa pamieci dzielonej, czas, podzielnik, reszta */ int czas,klucz,m,h,i; if(ac<3) { fprintf(stderr,usage,av[0]); return -1; } if(sscanf(av[2],"%d%n",&czas,&h)!=1 || av[2][h]!=0) { fprintf(stderr,"%s: to nie jest liczba\n",av[2]); return -1; } for(klucz=h=0; av[1][h]!=0; klucz=klucz*5+av[1][h++]); /* tworzymy jeden semafor; chcemy wiedziec, czy juz byl */ if((m=semget((key_t)klucz,1,IPC_CREAT|IPC_EXCL|0640))!=-1) /* nowy semafor - trzeba mu ustawic wartosc 1 */ if(sem_ustaw(m,1)==-1) goto end; else h=m; /* nie da sie utworzyc nowego - podlaczamy istniejacy */ else if((h=semget((key_t)klucz,1,0640))==-1) { perror("tworzenie semafora"); return -1; } while(czas-->0) { /* czekamy na semafor, i wypisujemy grupe cyfr */ sem_czekaj(h); for(i=0; i++<8; ) { poll(NULL,0,120); printf("%u",i); fflush(stdout); } /* pozwalamy dzialac innym procesom */ sem_sygnal(h); poll(NULL,0,1); /* to poll() jest konieczne - inaczej inne procesy * nie mialyby szans na zlapanie otwartego semafora */ } /* na koniec ktos powinien usunac semafor */ end: if(m!=-1) sem_usun(m); return 0; }