代码转自别处,稍有修改,主要是宏定义,我觉得不够直观的地方给改了,逻辑没变
用信号量来控制队列
#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