// Mon Apr 24 18:53:21 CEST 2000 // Dinko Korunic, 36355514, email: kreator@fly.srk.fer.hr // Predmet Operacijski sustavi 1 - Zadatak 4 // Opis rjesenja: // Opci semafori sa negativnim semaforima su izvedeni tako da je // definirana konstanta koja oznacava nulu i koja ima vrijednost // MAXSHORT/2 tako da sve vrijednosti manje od te konstante // predstavljaju negativne semafore, dok vrijednosti veci od // MAXSHORT/2 predstavljaju semafore vece od nule. Sinkronizacija // procesa za potrebnu strukturu je izvedena tako da je stablo // izvrsavanja upisano u jednu strukturu tako da je za svaki cvor // upisano koji su moguci njegovi slijedbenici. #include #include #include #include #include #include #include #include #include #include #define BITSPERBYTE 8 #define BITS(type) (BITSPERBYTE*(int)sizeof(type)) #define SHORTBITS BITS(short) #define MINSHORT ((short)(1<<(SHORTBITS-1))) #define MAXSHORT ((short)~MINSHORT) #define ZERO ((int)((MAXSHORT>>1)+1)) #define MYMAXLEN 128 #define BSEM 0 #define OSEM_PRAZAN 1 #define OSEM_PUN 2 //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 */ //}; class MyLowSem { public: int SemId; // identifikacijski broj semafora void Greska(char *); void SemGet(int); int SemSetVal(int, int); int SemOp(int, int); void SemRemove(void); }; void MyLowSem::Greska(char *mesg) { cout << mesg << endl; exit(EXIT_FAILURE); } void MyLowSem::SemGet(int n) { // dobavi skup semafora sa ukupno n semafora if ((SemId=semget(IPC_PRIVATE, n, 0600))==-1) { perror("SemGet"); Greska("Nema semafora!"); } } int MyLowSem::SemSetVal(int SemNum, int SemVal) { // postavi vrijednost semafora SemNum na SemVal union semun MyArg; MyArg.val=SemVal; int i=semctl(SemId, SemNum, SETVAL, MyArg); if (i==-1) perror("SemSetVal"); return i; } int MyLowSem::SemOp(int SemNum, int SemOp) { // obavi operaciju SemOp sa semaforom SemNum struct sembuf SemBuf; SemBuf.sem_num=SemNum; SemBuf.sem_op=SemOp; //SemBuf.sem_flg=SEM_UNDO; SemBuf.sem_flg=0; return semop(SemId, &SemBuf, 1); } void MyLowSem::SemRemove(void) { // unisti skup semafora semctl(SemId, 0, IPC_RMID); } class MyBSem : virtual public MyLowSem { public: int CekajBSem(int); int PostaviBSem(int); }; int MyBSem::CekajBSem(int SemNum) { // cekanje binarnog semafora #ifdef DEBUG cout << "CekajBSem(" << SemNum << ")" << endl; #endif int i=SemOp(SemNum, -MAXSHORT); if (i==-1) perror("CekajBSem"); return i; } int MyBSem::PostaviBSem(int SemNum) { // postavljanje binarnog semafora #ifdef DEBUG cout << "PostaviBSem(" << SemNum << ")" << endl; #endif // SemSetVal(SemNum, 0); int i=SemOp(SemNum, MAXSHORT); if (i==-1) perror("Postavi BSem"); return i; } class MyOSem : virtual public MyLowSem { public: int CekajOSem(int); int PostaviOSem(int); int PostaviVrijednostOSem(int, int); }; int MyOSem::CekajOSem(int SemNum) { // cekaj na opci semafor koji moze poprimiti negativne vrijednosti #ifdef DEBUG cout << "CekajOSem(" << SemNum << ")" << endl; #endif int i=SemOp(SemNum, -1); if (i==-1) perror("CekajOSem1"); // dodatak za negativne vrijednosti i=SemOp(SemNum, -ZERO); if (i==-1) perror("CekajOSem2"); i=SemOp(SemNum, ZERO); if (i==-1) perror("CekajOSem3"); return i; } int MyOSem::PostaviOSem(int SemNum) { // postavi opci semafor #ifdef DEBUG cout << "PostaviOSem(" << SemNum << ")" << endl; #endif return SemOp(SemNum, 1); } int MyOSem::PostaviVrijednostOSem(int SemNum, int Vrijednost) { // Postavi vrijednost opceg semafora (moze poprimiti negativne // vrijednosti) #ifdef DEBUG cout << "PostaviVrijednostOsem(" << SemNum << ")=" << Vrijednost << endl; #endif return SemSetVal(SemNum, ZERO+Vrijednost); } class Zadatak41 : public MyBSem { public: Zadatak41(); ~Zadatak41(); }; Zadatak41::Zadatak41() { // Ostvariti medjusobno iskljucivanje dva procesa koristenjem binarnog // semafora. SemGet(2); // dobavi jedan semafor SemSetVal(0, MAXSHORT); int i, k, m; for (i=0; i<=1; ++i) { if (!fork()) { // dijete cout << "dijete " << i << endl; for (k=1; k<=5; ++k) { CekajBSem(i); for(m=1; m<=10; ++m) { cout << i << " " << k << " " << m << endl; sleep(1); } PostaviBSem(!i); } _exit(EXIT_SUCCESS); } sleep(3); } wait(NULL); wait(NULL); } Zadatak41::~Zadatak41() { SemRemove(); } class Zadatak42 : public MyOSem { public: Zadatak42(); ~Zadatak42(); }; Zadatak42::Zadatak42() { // Koristenjem tako dobivenih opcih semafora ili operacija za rad sa // semaforima u UNIX-u, ostvariti sinkronizaciju sedam procesa prema // zadanom grafu (na primjer, Z3 smije poceti tek kada zavrse Z1 i Z2). int CekajOSemTable[7][4]={{0, 2, 0xdeadbeef, 0xdeadbeef}, {0, 1, 2, 0xdeadbeef}, {3, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef}, {3, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef}, {3, 4, 0xdeadbeef, 0xdeadbeef}, {0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef}, {0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef}}, OSemValueTable[5]={-1, 0, -1, -2, 0}; SemGet(5); int i; for (i=0; i<5; ++i) PostaviVrijednostOSem(i, OSemValueTable[i]); for (i=0; i<7; ++i) { if (!fork()) { cout << "process #" << i+1 << endl; if (i>1) CekajOSem(i-2); int j, k; for (j=1; j<=20-i; ++j) { cout << "i=" << i+1 << " j=" << j << endl; sleep(1); } sleep(1); for (k=0; CekajOSemTable[i][k]!=0xdeadbeef; ++k) PostaviOSem(CekajOSemTable[i][k]); _exit(EXIT_SUCCESS); } } for (i=0; i<7; ++i) wait(NULL); } Zadatak42::~Zadatak42() { SemRemove(); } class Zadatak43 : public MyOSem, public MyBSem { int ShMemId, *Ulaz; char *spremnik; void Proizvodjac(int); void Potrosac(void); public: Zadatak43(); ~Zadatak43(); }; Zadatak43::Zadatak43() { // Ostvariti komunikaciju medju procesima, koji se paralelno izvode, preko // medjuspremnika ogranicene duljine. Dva procesa proizvodjaca trebaju na // pocetku procitati niz znakova s tastature i nakon toga poslati znak po // znak preko medjuspremnika procesu tipa potrosac. Proces potrosac treba // primiti znak po znak od proizvodjaca i nakon sto je primio sve znakove // od oba proizvodjaca, treba ih ispisati na zaslonu. if ((ShMemId=shmget(IPC_PRIVATE, (2*MYMAXLEN+1)*sizeof(int), 0600))==-1) Greska("Neuspio shmget()"); spremnik=(char *)shmat(ShMemId, NULL, 0); Ulaz=(int *)spremnik; spremnik+=sizeof(int); *Ulaz=0; SemGet(3); SemSetVal(BSEM, MAXSHORT); PostaviVrijednostOSem(OSEM_PUN, MYMAXLEN); // prazna mjesta // u spremniku PostaviVrijednostOSem(OSEM_PRAZAN, 0); // broj znakova int i; for (i=0; i<2; ++i) { if (!fork()) { Proizvodjac(i); _exit(EXIT_SUCCESS); } } if (!fork()) { Potrosac(); _exit(EXIT_SUCCESS); } for (i=0; i<3; ++i) wait(NULL); } void Zadatak43::Proizvodjac(int ProizNum) { cout << "proizvodjac " << ProizNum << endl; CekajBSem(BSEM); char niz[MYMAXLEN]; cout << "unesi niz #" << ProizNum << " > "; cin >> niz; // cin.getline(niz, sizeof(niz)); PostaviBSem(BSEM); int i=0; do { CekajOSem(OSEM_PUN); CekajBSem(BSEM); *(spremnik+(*Ulaz))=niz[i]; ++(*Ulaz)%=MYMAXLEN; PostaviBSem(BSEM); PostaviOSem(OSEM_PRAZAN); } while (niz[i++]); } void Zadatak43::Potrosac(void) { cout << "potrosac" << endl; char niz[2*MYMAXLEN]; int Izlaz=0, i, j; for(i=0, j=0; j<2; ++i) { CekajOSem(OSEM_PRAZAN); niz[i]=*(spremnik+Izlaz); if (!niz[i]) { ++j; --i; } ++Izlaz%=MYMAXLEN; PostaviOSem(OSEM_PUN); } niz[i]=0; cout << "potrosac primio: " << niz << endl; } Zadatak43::~Zadatak43() { SemRemove(); shmdt((char *)Ulaz); shmctl(ShMemId, IPC_RMID, NULL); } void Unos(void) { int i=0; cout << "Unesi broj zadatka (1/2/3): " << endl; cin >> i; if (i==1) Zadatak41 MyOb; else if (i==2) Zadatak42 MyOb; else if (i==3) Zadatak43 MyOb; else cout << "Krivi izbor!" << endl; } int main(void) { Unos(); return EXIT_SUCCESS; }