/* Aaron Linville aaron@linville.org http://www.linville.org Synchronized producer and consumers with semaphores. */ #define SHMPERM 0600 // octal #define SEMPERM 0600 // octal #include #include #include #include #include #include #include #include int p(int); // Wait int v(int); // Signal union { int val; struct semid_ds *buffer; ushort *array; } eenum; union { int val; struct semid_ds *buffer; ushort *array; } snum; union { int val; struct semid_ds *buffer; ushort *array; } nnum; int main() { int pid, semids, semidn, semide, shmid, stat_loc; char *shm, *s; // Keys key_t key = IPC_PRIVATE; // Args to be passed to semget() int nsems = 1; int semflg = IPC_CREAT | IPC_EXCL | SEMPERM; // Args to be passed to shmget() int size = 10; int shmflg = IPC_CREAT | IPC_EXCL | SHMPERM; // Get semaphore s, n, and e if(((semids = semget(key, nsems, semflg)) < 0) || ((semidn = semget(key, nsems, semflg)) < 0) || ((semide = semget(key, nsems, semflg)) < 0)) { cerr << "Unable to get one of the semaphores! Errno: " << errno << endl; return 0; } snum.val = 1; nnum.val = 0; eenum.val = 10; if((semctl(semids, 0, SETVAL, snum) == -1) || (semctl(semidn, 0, SETVAL, nnum) == -1) || (semctl(semide, 0, SETVAL, eenum) == -1)) { cerr << "Unable to set the value on a semaphore! Errno: " << errno << endl; return 0; } // Get shared memory if((shmid = shmget(key, size, shmflg)) < 0) { cerr << "Unable to get shared memory! Errno: " << errno << endl; return 0; } if((pid = fork()) < 0) { cerr << "Unable to fork! Errno: " << errno << endl; return 0; } else { if(pid == 0) { // Consumer if((shm = (char *) shmat(shmid, NULL, 0)) == (void *) -1) { cerr << "Consumer unable to attach! Errno: " << errno << endl; return 0; } // Consume the first 100 items // 10 byte buffer means read it 10 times for(int i = 0; i < 10; i++) { s = shm; for(int j = 0; j < 10; j++) { p(semidn); p(semids); cout << int(*s++) << endl; v(semids); v(semide); } } return 0; } else { // Producer if((shm = (char *) shmat(shmid, NULL, 0)) == (void *) -1) { cerr << "Producer unable to attach! Errno: " << errno << endl; return 0; } // Produce the first 100 numbers // 10 byte buffer means fill it 10 times for(int i = 0; i < 10; i++) { s = shm; for(int j = 0; j < 10; j++) { p(semide); p(semids); *s++ = (i * 10) + j; // I love pointer math. v(semids); v(semidn); } } if(wait(&stat_loc) == -1) cerr << "No child to wait for! Errno: " << errno << endl; if((semctl(semids, 0, IPC_RMID, NULL) == -1) || (semctl(semidn, 0, IPC_RMID, NULL) == -1) || (semctl(semide, 0, IPC_RMID, NULL) == -1)) cerr << "Unable to remove semaphore! Errno: " << errno << endl; if(shmctl(shmid, IPC_RMID, NULL) == -1) cerr << "Unable to destroy segment! Errno: " << errno << endl; } } return 0; } // Perform wait int p(int semid) { struct sembuf p_buf; p_buf.sem_num = 0; p_buf.sem_op = -1; p_buf.sem_flg = 0; if (semop(semid, &p_buf, 1) < 0) { cerr << "Fatal wait error on semaphore " << semid << endl; return -1; } return 0; } // Perform signal int v(int semid) { struct sembuf v_buf; v_buf.sem_num = 0; v_buf.sem_op = 1; v_buf.sem_flg = 0; if(semop(semid, &v_buf, 1) < 0) { cerr << "Fatal signal error on semaphore " << semid << endl; return -1; } return 0; }