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

只开了一块缓冲区,所以不需要用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()函数真的是一个非常好用的便于观察和思考的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值