Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1148501
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2279
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: LINUX

2016-09-06 11:17:06

IPC/sem.c
kernel中include/uapi/linux/sem.h

/* semop system calls takes an array of these. */
struct sembuf {
    unsigned short  sem_num;    /* semaphore index in array */要操作的信号灯的编号
    short        sem_op;        /* semaphore operation */ 0 ---- 等待  +1 V操作 释放资源  -1 P操作
    short        sem_flg;    /* operation flags */ 0,IPC_NOWAIT,SEM_UNDO
    //SEM_UNDO 自动平衡信号量(因进程异常推出后系统给这个进程所加的锁给以释放(或者反向))
};

include/uapi/linux/sem.h
/* arg for semctl system calls. */
union semun {
    int val;            /* value for SETVAL */
    struct semid_ds __user *buf;    /* buffer for IPC_STAT & IPC_SET */
    unsigned short __user *array;    /* array for GETALL & SETALL */
    struct seminfo __user *__buf;    /* buffer for IPC_INFO */
    void __user *__pad;
};


//////////////////////////////////////////////////////////////
pre.ctl { font-family: "Liberation Mono",monospace; }p { margin-bottom: 0.25cm; line-height: 120%; } #include "sem_comm.h"
/* 封装 信号量的操作函数*/

/* 信号量的初始化 */
int init_sem(int semid, int semnum, int init_val)
{
   union semun sun;
   sun.val = init_val;
   return semctl(semid, semnum, SETVAL, sun);
}

/*信号量的删除 */
int del_sem(int semid)
{
    return semctl(semid, 0, IPC_RMID,0);
}

/*信号量的P操作 */
int sem_p(int semid, int sem_num, unsigned int nsops)
{
    struct sembuf sbuf;
    sbuf.sem_num = sem_num;
    sbuf.sem_op = -1;
    sbuf.sem_flg = SEM_UNDO;
    
    return semop(semid, &sbuf, nsops);
}

/*信号量的V操作 */
int sem_v(int semid, int sem_num, unsigned int nsops)
{
    struct sembuf sbuf;
    sbuf.sem_num = sem_num;
    sbuf.sem_op = 1;
    sbuf.sem_flg = SEM_UNDO;

    return semop(semid, &sbuf, nsops);
}


    
/*信号量的非阻塞P操作 */
int sem_try_p(int semid, int sem_num, unsigned int nsops)
{
    struct sembuf sbuf;
    sbuf.sem_num = sem_num;
    sbuf.sem_op = -1;
    sbuf.sem_flg = IPC_NOWAIT|SEM_UNDO;

    return semop(semid, &sbuf, nsops);
}
    
/////////////////////////////////////////////////////////
shm_write.c
#include
#include
#include
#include
   #include
       #include
       #include

#include "sem_comm.h"

#define SHM_KEY_PATH "."
#define SHM_KEY_ID 'a'

#define SEM_KEY_PATH "."
#define SEM_KEY_PRJ_ID 'b'

#define SHM_SIZE 2048
#define QUIT_STR "quit"

#define SEM_R 0
#define SEM_W 1

int main(void)
{
    int shm_id = -1, sem_id = -1;
    char *pShm = NULL;

       
    /* 1. 创建共享内存和信号量*/
    if((shm_id = shmget(ftok(SHM_KEY_PATH, SHM_KEY_ID), SHM_SIZE, IPC_CREAT|0666)) < 0) {
    perror("shmget");
    exit(1);
    }
    if( (sem_id = semget(ftok(SEM_KEY_PATH, SEM_KEY_PRJ_ID), 2, IPC_CREAT|0666)) < 0 ) {
        perror("semget");
        exit(1);
    }

    
    /*2. 映射共享内存和初始化信号量 */
    if((pShm = shmat(shm_id, NULL, 0)) == (void *)-1) {
    perror("shmat");
    exit(1);
    }
    /*信号量初始化成写可用,读不可用*/
    init_sem(sem_id, SEM_R, 0);
    init_sem(sem_id, SEM_W, 1);

    /* 3. 从标准键盘上获取用户的输入,写入到共享内存*/

    char buf[BUFSIZ];
    while(1) {
            fprintf(stderr, "Please input string: ");
            bzero(buf, BUFSIZ);
            if( fgets(buf, BUFSIZ-1,stdin) == NULL) {
                perror("fgets");
                continue;
            }
            buf[BUFSIZ-1] = '\0';  /* 防止数组下标越界*/
        
        int len = strlen(buf);
        
        sem_p(sem_id, SEM_W, 1); //Psem_w操作
        
        bzero(pShm,SHM_SIZE);
        /* 加入一个len是为了防止数组下标越界*/
        if(len > SHM_SIZE -1) {
        len = SHM_SIZE -1;
        }
            strncpy(pShm, buf, len);

            if(!strncasecmp(pShm, QUIT_STR, strlen(QUIT_STR))) { //用户输入了"quit"
                sem_v(sem_id, SEM_R, 1); //Vsem_r操作
        break;
            }

         sem_v(sem_id, SEM_R, 1); //Vsem_r操作

    }


    /*4. 撤销映射*/
    shmdt(pShm);
    pShm = NULL;
     
    /*5.删除共享内存*/
  //  shmctl(shm_id, IPC_RMID, NULL);

    return 0;
};
/////////////////////////////////////////
shm_reader.c
#include
#include
#include
#include
#include
#include
#include

#include "sem_comm.h"

#define SHM_KEY_PATH "."
#define SHM_KEY_ID 'a'

#define SEM_KEY_PATH "."
#define SEM_KEY_PRJ_ID 'b'

/*在内核中的信号量数组的下标 */
#define SEM_R 0
#define SEM_W 1


#define SHM_SIZE 2048
#define  QUIT_STR "quit"

int main(void)
{
    int shm_id = -1, sem_id = -1;
    char *pShm = NULL;


    /* 1. 打开共享内存和信号量*/
    if((shm_id = shmget(ftok(SHM_KEY_PATH, SHM_KEY_ID), SHM_SIZE, IPC_CREAT|0666)) < 0) {
        perror("shmget");
        exit(1);
    }
//注意semget获取两个信号量的用法
//见IPC/sem.c          SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg) 查看semget这个系统调用的实现
    if( (sem_id = semget(ftok(SEM_KEY_PATH, SEM_KEY_PRJ_ID), 2, IPC_CREAT|0666)) < 0 ) {
        perror("semget");
        exit(1);
    }


    /*2. 映射共享内存 */
    if((pShm = shmat(shm_id, NULL, 0)) == (void *)-1) {
        perror("shmat");
        exit(1);
    }


    /*3. 读共享内存 */
    while(1) {
    sem_p(sem_id, SEM_R, 1); //Psem_r操作

    if(strlen(pShm)) {
        printf("Reader: %s\n", pShm);
        if(!strncasecmp(pShm, QUIT_STR, strlen(QUIT_STR))) { //用户输入了"quit"
        sem_v(sem_id, SEM_W, 1); //Vsem_w操作
        break;
        }

        bzero(pShm, BUFSIZ);
    }
    sem_v(sem_id, SEM_W, 1); //Vsem_w操作
    
    }

    /*4. 撤销映射*/
    shmdt(pShm);
    pShm = NULL;
     
    /*5.删除共享内存和信号量*/
    shmctl(shm_id, IPC_RMID, NULL);
    del_sem(sem_id);
    return 0;
};
//////////////////////////////////////////////////////////////////////////////////








阅读(1209) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~