多读者多写者对两个缓冲区的操作实现(reader)_ 冷殇<_百度空间

/*
*
多读者多写者对两个缓冲区的操作实现
*
原理:通常信号灯与共享内存一起使用可实现操作的同步
*
读者按写者的顺序读数据
*
设定写者先都向buf[0]中写,读者先从buf[0]中读
*
计数信号灯,用来统计资源,其值代表资源数
*
共有四类资源:可读缓冲区sem_r,可写缓冲区sem_w
*
读的位置pos_r,写的位置pos_w(都用于指定读和写的位置buf[0]还是
buf[1])
*
注意pos_rpos_w为临界资源,可用二值信号灯加锁

*
所以要设置四个信号灯(编号从0-3)
*
一个程序为一个进程,先运行的程序,要创建共享内存,创建信号灯及其初始化

* */
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>

#define SIZE 64
#define SEM_N 4     //
信号灯个数
#define SEM_R 0     //
读者信号灯编号 资源数为0
#define SEM_W 1     //
写者
..           2
#define SEM_LR 2    //
读者锁(由二值信号灯实现
)..    1
#define SEM_LW 3    //
写者锁
..          1  

//
定义共享内存结构体

//
共享内存包括两个四字节的位置参数,还有两个64字节的缓冲区
struct _shm_{
    int pos_r,pos_w;   
    char buf[2][SIZE];
};

//arg for semctl system calls
union semun{
    int val;    //value for SETVAL
    struct semid_ds *buf;   //Buffer for IPC_STAT,IPC_SET
    unsigned short *array; //Array for GETALL,SETALL
    struct seminfo *__buf; //Buffer for IPC_INFO
};

//
定义初始化信号灯的参数
//semid
为要修改信号量的ID
void sem_init(int semid,int array[],int num)
{
    int i;
    union semun sem;

    //i
为信号灯编号,
    for(i = 0;i < num;i++)
    {
        //
设置编号为i的信号灯个数即有的资源个数
        sem.val = array[i];
        //
指定了命令参数为SETVAL时只要设置sem.val
        semctl(semid,i,SETVAL,sem);
    }
    return;
}

//pv
操作函数实质是系统调用semop的操作

//
对信号灯集semid中编号为num的信号灯进行op操作
void pv(int semid,int num,int op)
{
    struct sembuf sem; //struct sembuf
描述对某一个信号灯的操作

    sem.sem_num = num;
    sem.sem_op = op;    //-1
表分配资源p操作,1表释放由某一信号灯控制的资源v操作
    sem.sem_flg = 0;    //0
表申请不成功就阻塞

    semop(semid,&sem,1);    //1
表对一个信号灯进行操作

    return;
}

int main(int argc,char *argv[])
{
    key_t key;
    int shmid,semid;    //shared-memory id && semaphoreV id
    int init_array[] = {0,2,1,1};   //
四类资源分别有多少
    struct _shm_ *shmaddr; //
定义共享内存的结构体指针,用于映射

    //
不同的对象可使用相同的key
    if((key = ftok("./",'s')) < 0){
        perror("key make error.\n");
        exit(-1);
    }
    //
{dy}个进程进行共享内存的创建,信号灯集的创建和初始化操作

    if((shmid = shmget(key,sizeof(struct _shm_),IPC_CREAT|IPC_EXCL|0666)) < 0){//
不是{dy}个进程
        if(EEXIST == errno){
            shmid = shmget(key,sizeof(struct _shm_),0666);//
打开共享内存
            //NULL
表将共享内存映射到此进程地址空间,0表以读写方式
            shmaddr = (struct _shm_ *)shmat(shmid,NULL,0);
            semid = semget(key,SEM_N,0666); //
打开信号灯集
        }
    }
    else{   //
是{dy}个进程,共享内存创建之后创建信号灯集
        shmaddr = (struct _shm_ *)shmat(shmid,NULL,0);
        shmaddr->pos_r = 0; //
指定初始读的位置
        shmaddr->pos_w = 0; //
指定初始写的位置
        //
创建信号灯集
        if((semid = semget(key,SEM_N,IPC_CREAT|0666)) < 0){
            perror("semget error.\n");
            exit(-1);
        }

        //
对信号灯集的初始化
        sem_init(semid,init_array,SEM_N);
    }

   
    //
读者
    while(1)
    {
        pv(semid,SEM_R,-1); //
申请不成功则阻塞
        pv(semid,SEM_LR,-1);    //
通过二值信号灯SEM_LR对临界资源pos_r进行保护
        printf("read from shm : %s",shmaddr->buf[shmaddr->pos_r]);
        shmaddr->pos_r = (shmaddr->pos_r + 1) % 2;
        pv(semid,SEM_LR,1); //
释放临界资源pos_r以使其它读者进程可访问
        pv(semid,SEM_W,1); //
当一个进程读完以后,释放一个控制的可写缓冲区
    }

    return 0;
}



郑重声明:资讯 【多读者多写者对两个缓冲区的操作实现(reader)_ 冷殇<_百度空间】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——