生产者-消费者问题实现

#include <stdio.h>

#include <time.h>

#include <unistd.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/sem.h>

#define NEED_P 2       //生产者进程数

#define NEED_C 2       //消费者进程数

#define WORKS_P 10    //每个生产者进程执行的次数

#define WORKS_C 10    //每个消费者进程执行的次数

#define BUF_LENGTH (sizeof(struct mybuffer))     //共享内存的大小

#define BUF_NUM  10                         //缓冲区的大小

#define SHM_MODE  0600

#define SEM_ALL_KEY  2411

#define SEM_EMPTY  0                //空的信号量

#define SEM_FULL  1                  //满的信号量

//缓冲区结构(循环队列)

struct mybuffer

{

    char letter[BUF_NUM];

    int head;

    int tail;

    int is_empty;

};

//得到5以内的一个随机数

int get_random()

{

    int t;

    srand((unsigned)(getpid() + time(NULL)));

    t = rand() % 5;

    return t;

}

//得到A~Z的一个随机字母

char get_char()

{

    char a;

    srand((unsigned)(getpid() + time(NULL)));

    a = (char)((char)(rand() % 26) + 'A');

    return a;

}

//P操作

void p(int sem_id, int sem_num)  

{

    struct sembuf pc;

    pc.sem_num = sem_num;    //信号量的类型

    pc.sem_op = -1;           //操作类型

    pc.sem_flg = 0;          //操作的标志

    semop(sem_id, &pc, 1);

}

//V操作

void v(int sem_id, int sem_num)

{

    struct sembuf pc;

    pc.sem_num = sem_num;

    pc.sem_op = 1;

    pc.sem_flg = 0;

    semop(sem_id, &pc, 1);

}

//主函数

int main(int argc, char * argv[])

{

    int i, j;

    int shm_id, sem_id;

    int num_p = 0, num_c = 0;

    struct mybuffer * shmptr;

    char lt;

    time_t now;

    pid_t pid_p, pid_c;      

    sem_id = semget(SEM_ALL_KEY, 2, IPC_CREAT | 0600);    //建立信号量,建立的信号量数量为2,返回此信号量的ID

    if (sem_id >= 0)

    {

        printf("Main process starts. Semaphore created.\n");

    }

    semctl(sem_id, SEM_EMPTY, SETVAL, BUF_NUM);    //初始设置第一个信号量SE_EMPTY的值为BUF_NUM

    semctl(sem_id, SEM_FULL, SETVAL, 0);          //初始设置第二个信号量SE_FULL的值为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;    

    while ((num_p++) < NEED_P)

    {

        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(sem_id, SEM_EMPTY);

                sleep(get_random());

                shmptr->letter[shmptr->tail] = lt = get_char();

                shmptr->tail = (shmptr->tail + 1) % BUF_NUM;

                shmptr->is_empty = 0;

                now = time(NULL);

                printf("%02d:%02d:%02d\t", localtime(&now)->tm_hour, localtime(&now)->tm_min, localtime(&now)->tm_sec);

                for (j = (shmptr->tail - 1 >= shmptr->head) ? (shmptr->tail - 1) : (shmptr->tail - 1 + BUF_NUM); !(shmptr->is_empty) && j >= shmptr->head; j--)

                {

                    printf("%c", shmptr->letter[j % BUF_NUM]);

                }

                printf("\tProducer %d puts '%c'.\n", num_p, lt);

                fflush(stdout);              //刷新缓冲区

                v(sem_id, SEM_FULL);

            }

            shmdt(shmptr);      //分离共享内存

            exit(0);

        }

    }

    while (num_c++ < NEED_C)

    {

        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(sem_id, SEM_FULL);

                sleep(get_random());

                lt = shmptr->letter[shmptr->head];

                shmptr->head = (shmptr->head + 1) % BUF_NUM;

                shmptr->is_empty = (shmptr->head == shmptr->tail);

                now = time(NULL);

                printf("%02d:%02d:%02d\t", localtime(&now)->tm_hour, localtime(&now)->tm_min, localtime(&now)->tm_sec);

                for (j = (shmptr->tail - 1 >= shmptr->head) ? (shmptr->tail - 1) : (shmptr->tail - 1 + BUF_NUM); !(shmptr->is_empty) && j >= shmptr->head; j--)

                {

                    printf("%c", shmptr->letter[j % BUF_NUM]);

                }

                printf("\tConsumer %d gets '%c'.\n", num_c, lt);

                fflush(stdout);

                v(sem_id, SEM_EMPTY);

            }

            shmdt(shmptr);

            exit(0);

        }

    }

    //主控程序最后退出

    while(wait(0) != -1);

    shmdt(shmptr);                    //分离共享内存

    shmctl(shm_id, IPC_RMID, 0);       //撤销共享内存

    semctl(sem_id, IPC_RMID, 0);       //释放内存

    printf("Main process ends.\n");

    fflush(stdout);

    exit(0);

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值