【Linux学习笔记】39:Linux下C模拟读者写者问题

来源:互联网 发布:杭州腾亿网络 编辑:程序博客网 时间:2024/05/21 09:22

只开了一块缓冲区,所以不需要用mutex互斥信号量对其保护,直接交替PV操作就行了。应当找时间系统学习一下Linux下的C/C++编程,有很多有意思的功能。下面两个程序可以开两个terminal,编译好后,先执行生产者,再在另一个terminal里执行消费者的程序,然后在生产者的程序里输入(生产的)字符串就行了。因为用的是scanf的%s读入字符串,所以中间有空格时会陆续读入,这种时候观察两个进程的状态挺有意思。

生产者程序

#include<stdio.h>#include<sys/ipc.h>#include<sys/shm.h>#include<stdlib.h>#include<sys/stat.h>#include<sys/sem.h>#define SEM_KEY 6666#define true 1#define false 0//共用体union semun {    int setval;    struct semid_ds *buf;    unsigned short *array;};int main(int argc ,char *argv[]){    int shmid;//信号量的标识码ID,创建失败时为-1    char *addr;//公用缓冲区(共享内存)首地址    //shmget()创建一个共享内存,权限为0666    shmid=shmget(ftok(".",1000),getpagesize(),IPC_CREAT  | 0666);    //创建失败时为-1    if(shmid==-1)    {       perror("shmget error:");       exit(EXIT_FAILURE);    }    //输出共享内存的标识码ID    printf("共享内存的标识码ID:=%d\n",shmid);    //获取共享内存的起始地址,且为可读可写    addr=shmat(shmid,0,0);    //获取失败时为-1    if(-1==*addr)    {       perror("shmat error:");       exit(EXIT_FAILURE);    }    /*    int semget(key_t _key,int _nsems,int _semflg);    功能:创建一个新的信号量或获取一个已经存在的信号量的键值。    */    //创建2个信号量的信号集    int semid=semget(SEM_KEY, 2, IPC_CREAT | 0600);    //创建失败时为-1    if (-1 == semid)    {       perror("semget");       exit(EXIT_FAILURE);    }    printf("信号集的标识码ID:=%d\n", semid);    //初始化信号集    union semun sem_args;    unsigned short array[2]={0,1};    sem_args.array = array;//赋值给共用体    //SETALL代表设置信号集中所有的信号量的值。1,代表2个,sem_args是具体初始化的值放在共用体中     int ret=semctl(semid, 1, SETALL, sem_args);    //设置失败时为-1    if (-1 == ret)    {       perror("semctl");       exit(EXIT_FAILURE);    }    //对资源的使用处理操作    /*    struct sembuf{     unsigned short sem_num;//第几个信号量,第一个信号量为0     short sem_op;//对该信号量的操作(+/-)     short sem_flg;//常被设置为SEM_UNDO,使得如果一个进程在没有释放信号量的情况下结束了执行,该进程掌握的信号量由系统自己释放    };    */    struct sembuf P_full={0, -1, SEM_UNDO};    struct sembuf V_full={0, +1, SEM_UNDO};    struct sembuf P_empty={1, -1, SEM_UNDO};    struct sembuf V_empty={1, +1, SEM_UNDO};    printf("<这里是生产者进程,在这里输入生产出的字符串>\n");    //不断生产    while(true)    {        /*        int semop(int semid ,struct sembuf *_sops ,size_t _nsops);        功能:用户改变信号量的值。也就是使用资源还是释放资源使用权        */        semop(semid, &P_empty, 1);//P(empty)等待至空缓冲区数量不为0        scanf("%s",addr);        printf(">%s被读入了缓冲区\n",addr);        semop(semid, &V_full, 1);//V(full)满缓冲区数量+1        if(addr[0]=='@')            break;//跳出循环,准备结束程序    }return 0;}

消费者程序

#include<stdio.h>#include<sys/ipc.h>#include<sys/shm.h>#include<stdlib.h>#include<sys/sem.h>#include<string.h>#include<sys/stat.h>#define SEM_KEY 6666#define true 1#define false 0//共用体union semun {    int setval;    struct semid_ds *buf;    unsigned short *array;};int main(int argc ,char *argv[]){    int shmid;//信号量的标识码ID,创建失败时为-1    char *addr;//公用缓冲区首地址    //打开刚才原程序1创建的共享内存,权限为0666    shmid= shmget(ftok(".",1000),getpagesize(), IPC_CREAT | 0666);    printf("共享内存的标识码ID:=%d\n",shmid);    //创建失败时为-1    if(shmid==-1)    {       perror("shmget error:");       exit(EXIT_FAILURE);    }    addr=shmat(shmid,0,0);//获取共享内存的起始地址,且为可读可写    if(-1==*addr)    {       perror("shmat error:");       exit(EXIT_FAILURE);    }    int semid=semget(SEM_KEY, 0, IPC_CREAT | 0600);//取得信号量    if(-1==semid)    {       perror("semget");       exit(EXIT_FAILURE);    }    printf("信号集的标识码ID:=%d\n", semid);    //对资源的使用处理操作    struct sembuf P_full={0, -1, SEM_UNDO};    struct sembuf V_full={0, +1, SEM_UNDO};    struct sembuf P_empty={1, -1, SEM_UNDO};    struct sembuf V_empty={1, +1, SEM_UNDO};    printf("<这里是消费者进程,不要在这里输入任何东西>\n");    //不断消费    while(true)    {        semop(semid, &P_full, 1);//P(full)等待至满缓冲区数量不为0        //如果检测到生产者输入的第一个字符是@        if(addr[0]=='@')            break;//跳出循环,准备结束程序        printf("消费ing...\n");        sleep(3);//消费需要时间        printf(">消费了");        puts(addr);//输出这次消费的东西        semop(semid, &V_empty, 1);//V(empty)空缓冲区数量+1    }    if(-1==semctl(semid,1,IPC_RMID,0))//删除信号量    {       perror("semctl error:");       exit(EXIT_FAILURE);    }    if(-1==shmdt(addr))//释放共享内存,使其不再有任何指向它的指针    {       perror("shmdt error:");       exit(EXIT_FAILURE);    }    if (shmctl(shmid,IPC_RMID,0)==-1)//删除共享内存    {       perror("shctl error:");       exit(EXIT_FAILURE);    }return 0;}

输入@符号就可以结束两个进程了,下面是运行的结果。
这里写图片描述
在做和进程有关的编程学习时,sleep()函数真的是一个非常好用的便于观察和思考的方法。

原创粉丝点击