进程同步与互斥,生产者和消费者问题

在linux下创建三个生产进程一个消费者进程,共享长度为10KB的环形公共缓冲区;描述数据定义,算法设计,流程图,源代码及注释,运行结果截图等

生产者和消费者两个程序,共用一个仓库,仓库是一个普通文件(/tmp/store),容量为100个字节;
生产者生产资源放进仓库,消费者则从仓库中消费资源;资源为数字字符“0~9”,一个资源就是一个数字,10个数字循环生成;
生产者创建仓库(/tmp/store),间隔1s生产一个资源,当仓库满了(资源数量达到100个)的时候,生产者不能继续生产;消费者间隔2s消费一个资源,当仓库为空的时候,消费者不能继续消费;
消费者每次消费1个资源,首先打印出消耗之前仓库中的资源数量和空位的数量,然后打印出消耗之后仓库中的资源数量和空位的数量,并打印出所消耗的资源内容;
生产者每次生产1个资源,先打印出生产之前仓库中的资源数量和空位的数量,然后打印出生产之后仓库中的资源数量和空位的数量,并打印出所生产的资源内容。
消费者消费资源后需要把已经消费的资源从仓库里删除;
用信号量实现进程的同步和互斥。

生产者:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/sem.h>
 
int semid;
 
union semun
{
    int val;
};
//初始化
void sem_init()
{
        //semget:创建一个新信号量或者获取一个已有的信号量的键
        semid=semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);//1234:房间号,0600->文件权限
        if(semid==-1)   //全新创建失败,获取已经存在的信号量
        {
                semid=semget((key_t)1234,1,0600);
                if(semid==-1)
                {
                        perror("semget error");
                }
                else
                {
                        //初始化
                        union semun a;//定义联合体
                        a.val=1;//初始化设置为1,假设刚开始可以使用
                        //semctl:用来直接控制信号量信息
                        if(semctl(semid,0,SETVAL,a)==-1)//编号从0开始
                        {
                                perror("semctl init error");
                        }
                }
        }
}
 
void sem_p()//p操作
{
        struct sembuf buf;
        buf.sem_num=0;
        buf.sem_op=-1;
        buf.sem_flg=SEM_UNDO;//一般都这样设置,是让操作系统记住使用了P操作
        //semop:对信号量进行改变,做p或者v操作
        if(semop(semid,&buf,1)==-1)//1:长度,只有一个信号量
                perror("p perror");
}
 
void sem_v()//v操作
{
        struct sembuf buf;
        buf.sem_num=0;
        buf.sem_op=1;
        buf.sem_flg=SEM_UNDO;//一般都这样设置,是让操作系统记住使用了P操作
        if(semop(semid,&buf,1)==-1)//1:长度,只有一个信号量
                perror("v perror");
}
//销毁
void sem_destory()
{
        if(semctl(semid,0,IPC_RMID)==-1)
                perror("destory sem error");
}
 
int main()
{
        int i=0;
        int size=0;
        FILE* fp;
        //char sym[]={'0','1','2','3','4','5','6','7','8','9'};
        char ch;
 
        //信号量初始化
        sem_init();
        printf("This is the producer...\n");
        while(1)
        {
            sem_p();//
            fp = fopen("/tmp/store","a");
            size = ftell(fp); //
            printf("Before produce, resource number:%d,left position:%d\n",size,100-size);
 
            if(size >=100)
            {
                printf("The store is full! resource number:%d,left position:%d\n",size,100-size);
                fclose(fp);
            }else
            {
                ch = (char)('0'+i%10);
                printf("After produce, resource number:%d,left position:%d, ",size+1,99-size);
                printf("new resource:%c\n",ch);
                i++;
                fwrite(&ch,1,1,fp);
                fclose(fp);
            }
            sem_v();
            sleep(1);
        }
        sem_destory();
}

消费者:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/sem.h>
 
int semid;
 
union semun
{
    int val;
};
//初始化
void sem_init()
{
        //semget:创建一个新信号量或者获取一个已有的信号量的键
        semid=semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);//1234:房间号,0600->文件权限
        if(semid==-1)   //全新创建失败,获取已经存在的信号量
        {
                semid=semget((key_t)1234,1,0600);
                if(semid==-1)
                {
                        perror("semget error");
                }
                else
                {
                        //初始化
                        union semun a;//定义联合体
                        a.val=1;//初始化设置为1,假设刚开始可以使用
                        //semctl:用来直接控制信号量信息
                        if(semctl(semid,0,SETVAL,a)==-1)//编号从0开始
                        {
                                perror("semctl init error");
                        }
                }
        }
}
 
void sem_p()//p操作
{
        struct sembuf buf;
        buf.sem_num=0;
        buf.sem_op=-1;
        buf.sem_flg=SEM_UNDO;//一般都这样设置,是让操作系统记住使用了P操作
        //semop:对信号量进行改变,做p或者v操作
        if(semop(semid,&buf,1)==-1)//1:长度,只有一个信号量
                perror("p perror");
}
 
void sem_v()//v操作
{
        struct sembuf buf;
        buf.sem_num=0;
        buf.sem_op=1;
        buf.sem_flg=SEM_UNDO;//一般都这样设置,是让操作系统记住使用了P操作
        if(semop(semid,&buf,1)==-1)//1:长度,只有一个信号量
                perror("v perror");
}
//销毁
void sem_destory()
{
        if(semctl(semid,0,IPC_RMID)==-1)
                perror("destory sem error");
}
 
int main()
{
        int size=0;
        FILE* fp,*fp2;
        char ch[110]={0};
        int len,i;
        //信号量初始化
        sem_init();
        printf("This is a customer...\n");
        while(1)
        {
            sem_p();//
            memset(ch,0,110);
            fp = fopen("/tmp/store","r");
            fseek(fp,0,SEEK_END);
            size = ftell(fp); //
            fseek(fp,0,SEEK_SET);
            fread(ch,1,size,fp);
            fclose(fp);
 
            /*for(i=0;i<size;i++)
                printf("%c ",ch[i]);
            printf("\n");*/
 
            len = strlen(ch);
            ch[len] = 0;
 
            printf("Before use, resource number:%d, left position:%d\n",len,100-len);
            if(len == 0)
            {
                printf("The store is empty!\n");
            }
            else
            {
                printf("After use, resource number:%d, left position:%d, ",len-1,101-len);
                printf("the resource:%c\n",ch[0]);
                fp2 = fopen("/tmp/store","w");
                fwrite(ch+1,1,len-1,fp2);
                fclose(fp2);
            }
            sem_v();
            sleep(2);
        }
        sem_destory();
}