用信号量来控制队列
#include <stdio.h> #include <time.h> #include <unistd.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #define PRODUCER_NR 2 #define CONSUMER_NR 3 #define WORKS_P 6 #define WORKS_C 4 #define BUF_LENGTH (sizeof(struct mybuffer)) #define LETTER_NUM 3 #define SHM_MODE 0600 #define SEM_ALL_KEY 1234 #define SEM_PRODUCER 0 #define SEM_CONSUMER 1 struct mybuffer { char letter[LETTER_NUM]; int head; int tail; int is_empty; }; int get_random() { struct timeval tms; gettimeofday(&tms, NULL); srand((unsigned)(getpid() + tms.tv_sec + tms.tv_usec)); return rand() % 5; } char get_letter() { struct timeval tms; gettimeofday(&tms, NULL); srand((unsigned)(getpid() + tms.tv_sec + tms.tv_usec)); return (char)((char)(rand() % 26) + 'A'); } void p_decrement(int sem_id, int sem_num) { struct sembuf xx; xx.sem_num = sem_num; xx.sem_op = -1; xx.sem_flg = 0; semop(sem_id, &xx, 1); } void v_increment(int sem_id, int sem_num) { struct sembuf xx; xx.sem_num = sem_num; xx.sem_op = 1; xx.sem_flg = 0; semop(sem_id, &xx, 1); } int main(int argc, char * argv[]) { int i, j; int shm_id, sem_id; int producer_nr = 0, consumer_nr = 0; struct mybuffer *shmptr; char lt; time_t now; pid_t pid_p, pid_c; sem_id = semget(SEM_ALL_KEY, 2, IPC_CREAT | 0660); if (sem_id >= 0) { printf("Main process starts. Semaphore created.\n"); } semctl(sem_id, SEM_PRODUCER, SETVAL, LETTER_NUM); semctl(sem_id, SEM_CONSUMER, SETVAL, 0); if ((shm_id = shmget(IPC_PRIVATE, BUF_LENGTH, SHM_MODE)) < 0) { printf("Error on shmget.\n"); exit(1); } if ((shmptr = shmat(shm_id, 0, 0)) == (void *)-1) { printf("Error on shmat.\n"); exit(1); } shmptr->head = 0; shmptr->tail = 0; shmptr->is_empty = 1; /* create PRODUCER_NR child tasks as producers */ while ((producer_nr++) < PRODUCER_NR) { if ((pid_p = fork()) < 0) { printf("Error on fork.\n"); exit(1); } if (pid_p == 0) { if ((shmptr = shmat(shm_id, 0, 0)) == (void *)-1) { printf("Error on shmat.\n"); exit(1); } for (i = 0; i < WORKS_P; i++) { p_decrement(sem_id, SEM_PRODUCER); sleep(get_random()); shmptr->letter[shmptr->tail] = lt = get_letter(); shmptr->tail = (shmptr->tail + 1) % LETTER_NUM; shmptr->is_empty = 0; now = time(NULL); printf("\tProducer %d puts '%c'.\t====>\tqueue:\t", producer_nr, lt); for (j = (shmptr->tail - 1 >= shmptr->head) ? (shmptr->tail - 1) : (shmptr->tail - 1 + LETTER_NUM) ; !(shmptr->is_empty) && j >= shmptr->head ; j--) { printf("%c", shmptr->letter[j % LETTER_NUM]); } putchar('\n'); fflush(stdout); v_increment(sem_id, SEM_CONSUMER); } shmdt(shmptr); exit(0); } } /* create CONSUMER_NR child tasks as consumers */ while (consumer_nr++ < CONSUMER_NR) { if ((pid_c = fork()) < 0) { printf("Error on fork.\n"); exit(1); } if (pid_c == 0) { if ((shmptr = shmat(shm_id, 0, 0)) == (void *)-1) { printf("Error on shmat.\n"); exit(1); } for (i = 0; i < WORKS_C; i++) { p_decrement(sem_id, SEM_CONSUMER); sleep(get_random()); lt = shmptr->letter[shmptr->head]; shmptr->head = (shmptr->head + 1) % LETTER_NUM; shmptr->is_empty = (shmptr->head == shmptr->tail); now = time(NULL); printf("\tConsumer %d gets '%c'.\t====>\tqueue:\t", consumer_nr, lt); for (j = (shmptr->tail - 1 >= shmptr->head) ? (shmptr->tail - 1) : (shmptr->tail - 1 + LETTER_NUM) ; !(shmptr->is_empty) && j >= shmptr->head ; j--) { printf("%c", shmptr->letter[j % LETTER_NUM]); } putchar('\n'); fflush(stdout); v_increment(sem_id, SEM_PRODUCER); } shmdt(shmptr); exit(0); } } while(wait(0) != -1) { static int child_nr = 1; printf("exit child %d\n", child_nr++); } shmdt(shmptr); shmctl(shm_id, IPC_RMID, 0); semctl(sem_id, IPC_RMID, 0); printf("Main process ends.\n"); fflush(stdout); exit(0); }
ref: http://www.cnblogs.com/xkfz007/articles/2566445.html