消费者-生产者问题---进程的实现信号量

生产者-消费者问题是操作系统的经典问题,需求是这样的:在系统中创建一个共享内存区域,内存区有长度为1的浮点数组,两个进程分别对共享内存区进行操作,进程A复杂循环向共享内存区域写入数据,B复杂读取由进程A产生的数据。

为了更好的利用信号量,观察效果,A和B进程没有亲缘关系。代码如下

/*进程A,负责发送数据*/
#include <stdlib.h>
#include<unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<sys/sem.h>
#include <sys/msg.h>
#include<time.h>
typedef struct
{
   double buff_dat;
} SHAME_BUF;//共享内存数据类型
typedef union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
}SEMCTL_UNION;//信号量控制时所需要传递的参数类型

int main(void)
{
    int id_sem,id_shm,i=0;//信号量和共享内存标识符
    key_t key;//键值
    SEMCTL_UNION semctl_arg;// 联合类型变量
    struct sembuf semop_buf;//操作信号1的变量
    struct sembuf semop_buf2;//操作信号2的变量
    SHAME_BUF *shm_buf;//共享内存结构指针
    time_t t;
    srand((unsigned)time(&t));//随机数
    if((key=ftok("/etc/profile",2))<0)//生成键值
    {
        perror("ftok");
        exit(0);
    }
    if((id_sem=semget(key,2,IPC_CREAT|IPC_EXCL|0666))==-1)//创建信号量集合包含两个信号量
    {
        if(errno!=EEXIST)
        {
            perror("semget");
            exit(1);
        }
        if((id_sem=semget(key,2,0))<0)//获取已经存在的信号量集合
        {
            perror("semget");
            exit(2);
        }

    }
    printf("id_sem=%d\n",id_sem);//打印信号量集合的描述符号

    semctl_arg.val=0;//初始值为0
    /*必须清除*/
    memset(&semop_buf,0x00,sizeof(struct sembuf));
    memset(&semop_buf2,0x00,sizeof(struct sembuf));
    semop_buf.sem_num=0;//第一个信号
    semop_buf.sem_op=1;//设置信号量操作 V

    semop_buf2.sem_num=1;//信号集的第二个信号
    semop_buf2.sem_op=-1;//设置信号量操作 P

    if(semctl(id_sem,0,SETVAL,semctl_arg)<0)//设置信号量1初始值0
    {
        perror("semctl");
        exit(3);
    }
    if(semctl(id_sem,1,SETVAL,semctl_arg)<0)//设置信号量2初始值0
    {
        perror("semctl");
        exit(4);
    }
    if((id_shm=shmget(key,sizeof(SHAME_BUF),IPC_CREAT|0666))<0)//创建共享内存
    {
        perror("shmget");

        exit(5);
    }
    if((shm_buf=shmat(id_shm,NULL,0))==(void *)-1)//映射共享内存到本地
    {
        perror("shmat");
        exit(6);
    }
     printf("id_shm=%d\n",id_shm);//输出共享内存描述符号
     shm_buf->buff_dat=0;
     while(1)
    {

        shm_buf->buff_dat=(double)(rand()%100);//产生随机数
        sleep((unsigned int)rand()%4);//模仿A产生数据的速度不固定,可能相差0-3秒
        i++;
        printf ("send %d complete \n",i);//打印完成的信息
        if(semop(id_sem,&semop_buf,1)==-1)
        {
            //信号1要执行V操作,进程会继续执行,写入进程执行,读去进程因为执行P操作被阻塞,等待数据到来
            perror("semop");
        }
        if(semop(id_sem,&semop_buf2,1)==-1)
        {
            //信号2要执行P操作,被阻塞。等待另一个进程读取完毕
            perror("semop");
        }
        if(i==10)
        {
            break;
        }
     }
    shmctl(id_shm,IPC_RMID,0);//删除共享内存
    semctl(id_sem,IPC_RMID,0);//删除信号量
    return 0;
}

</pre><p></p><p><pre name="code" class="cpp">/*进程B,负责打印数据*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<sys/sem.h>
#include <sys/msg.h>
#include<time.h>
typedef struct
{
   double buff_dat;
} SHAME_BUF;//共享内存数据类型
typedef union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
}SEMCTL_UNION;//信号量控制时所需要传递的参数类型
int main(void)
{
    int id_sem,id_shm,i=0;//信号量和共享内存标识符
    struct sembuf semop_buf;//进行信号量操作时候需要的变量1
    struct sembuf semop_buf2;//进行信号量操作时候需要的变量2
    SHAME_BUF *shm_buf;//共享内存结构指针

    id_sem=32769;
    id_shm=17006600;// ipcs -m查看的

    memset(&semop_buf,0x00,sizeof(struct sembuf));
    memset(&semop_buf2,0x00,sizeof(struct sembuf));

    semop_buf.sem_num=0;//操作第二个信号
    semop_buf.sem_op=-1;//P操作
    semop_buf2.sem_num=1;//操作第二个信号
    semop_buf2.sem_op=1;//V操作
    //semop_buf.sem_flg=IPC_NOWAIT;
    if((shm_buf=shmat(id_shm,NULL,0))==(void *)-1)//映射共享内存到本地
    {
        perror("shmat");
        exit(0);
    }
    while(1)
    {
        /*执行P操作,如果不能执行通。该进程会被阻塞,如果可以执行通,说明发送进程已经写入数据*/
        if(semop(id_sem,&semop_buf,1)==-1)
        {
            perror("semop");
        }
        printf("the num %d data is %lf\n",i,shm_buf->buff_dat);//读共享内存发过来的数
        i++;//计数
        if(semop(id_sem,&semop_buf2,1)==-1)//执行V操作,该进程此刻被阻塞,直到发送进程
        {
            perror("semop");
        }
        if(i==10)
        {
            break;
        }

    }
    shmctl(id_shm,IPC_RMID,0);//删除共享内存
    semctl(id_sem,IPC_RMID,0);//删除信号量
    return 0;
}


 进程A负责向共享内存区写入数据,写完后,进程A阻塞,进程B开始打印,进程B打印完成后,A会继续写入,就这样一直重复十次.当初因为忘记了清零 

 memset(&semop_buf,0x00,sizeof(struct sembuf));
 memset(&semop_buf2,0x00,sizeof(struct sembuf));
出现了一些不愉快,参考 http://blog.csdn.net/sahusoft/article/details/9033901,非常感谢。前面几天一直学习linux操作系统的进程间通信,通过消费者生产者问题综合锻炼了下自己的能力,感觉有帮助,代码自己写,但是感觉收获很多。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值