Unix环境进程间通信(二)

1.1        共享内存

1.1.1   数据结构

struct shmid_ds {
struct ipc_perm  shm_perm;    /* 超作许可权数据结构指针 */

    int              shm_segsz;   /* 共享存储段大小 (bytes) */

    time_t          shm_atime;   /* 最后调用shmat时间 */

    time_t          shm_dtime;   /* 最后调用shmdt的时间 */

    time_t          shm_ctime;   /* 最后调用shmctl的改变的时间 */

    unsigned short   shm_cpid;    /*创建者的进程ID */

    unsigned short   shm_lpid;    /* 最后对共享存储段进行操作的进程ID */

short           shm_nattch;  /* 当前连接数 */
};

struct ipc_perm {

     key_t  key;
     ushort uid;   /* owner euid and egid */
     ushort gid;
     ushort cuid;  /* creator euid and egid */
     ushort cgid;
     ushort mode;  /* lower 9 bits of shmflg */
     ushort seq;   /* sequence number */
};

 

1.1.2   API

4.4 #include <sys/ipc.h>

#include <sys/shm.h>

打开创建存储段

int shmget(key_t key, size_t size, int shmflg);

返回:失败-1, 成功返回非负的共享存储段id

 

第一个参数key是共享存储关键字。它有特殊值IPC_PRIVATE表示总是创建一个进程私有的共享存储段。

key值不等于IPC_PRIVATE时,shmget动作取决于最后一个参数shmflg标志:

1. IPC_CREAT 单独设置此标志,当系统中不存在相同key时,创建一个新的共享存储段,否则返回已存在的共享存储段。

2. IPC_EXCL 单独设置不起作用。与 IPC_CREAT同时设置时,当系统中存在相同key时,错误返回。保证不会打开一个已存在的共享存储段。

如果没有指定IPC_CREATE并且系统中不存在相同key值的共享存储段,将失败返回。

第三个参数也可以设置共享存储段的访问权限,用或于上面的值操作。

第二个参数size指明要求的共享存储段的大小。当key指定的共享存储段已存在时,取值范围为0和已存在共享段大小。或简单指定为0

成功后此函数返回共享存储段id,同时创建于参数key相连的数据结构shmid_ds。此节构为系统内部使用。

 

4.4 #include <sys/ipc.h>

#include <sys/shm.h>

存储段控制函数。可获得shmid_ds全部内容

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

返回:失败-1并置errno, 成功返回0

第一个参数,必须由shmget返回的存储段的idcmd为指定要求的操作。

CMD

说明

参数

IPC_STAT

放置与shmid相连的shmid_ds结构当前值于buf所指定用户区

buf

IPC_SET

buf指定的结构值代替与shmid相连的shmid_ds结构值

buf

IPC_RMID

删除制定的信号量集合

 

SHM_LOCK

锁住共享存储段。只能由超级管理员使用

 

SHM_UNLOCK

unlock共享存储段。只能由超级管理员使用

 

 

//创建/打开共享存储段,连接他到用户地址空间,返回他在用户空间的地址

void* shminit(key_t key, char* mode_str, int target=1) {

       int shmid;

       int mode;

       void* retval;

       if (mode_str == NULL) {

              mode = 0660;

       } else {

              sscanf(mode_str, "%o", &mode);

       }

       if (target == 0 ) {

              if ((shmid = shmget(key, sizeof(exchange_T), mode | IPC_CREAT)) == -1)

                     perror("cannot create shm--");

       } else if (target == 1) {

              if ((shmid = shmget(key, sizeof(exchange_T), mode)) == -1)

                     perror("cannot get shm--");

       }

       if ((retval = shmat(shmid, (void *)0, 0)) == (void*)-1)

              perror("shmmat");

       return retval;

}

 

int rm_shm(key_t key) {

       int status, shmid;

      

       if ((shmid = shmget(key, sizeof(exchange_T), 0x660 | IPC_CREAT)) < 0)

                     perror("cannot get shm");

       if ((status = shmctl(shmid, IPC_RMID, NULL)) < 0)

              perror("shmctl IPC_RMID");

       return status;

}

 

4.5 #include <sys/types.h>

   #include <sys/shm.h>

存储段连接

void *shmat(int shmid, const void *shmaddr, int shmflg);

返回:失败-1并置errno, 成功返回连接的实际地址

第一个参数,必须由shmget返回的存储段的id

第二个参数指明共享存储段要连接到的地址。0,系统为我们创建一个适当的地址值。否则自己指定

第三个参数shmflg可以设成:SHM_RND, SHM_RDONLYSHM_RND为自己指定连接地址时用。SHM_RDONLY说明此存储段只读。

 

4.6 #include <sys/types.h>

   #include <sys/shm.h>

存储段分离

int shmdt(const void * shmaddr);

返回:失败-1并置errno, 成功返回0

分离由shmaddr指定的存储段。此值应该由shmat返回的值。

此函数不是删除共享存储段,而是从当前进程分离存储段。

当进程推出时,系统会自动分离它连接的所有共享段。

1.1.3   Example

client.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>

#define SHMSZ 27
int main(void) {
       exchange_T* shm;
       int producer, consumer, i;
       key_t key1 = 123, key2 = 456;

       consumer = open_semaphore_set(key1, 1);
       procuder = open_semaphore_set(key2, 1);

       shm = (exchange_T*)shminit(ftock("shared", 0));

       for (i = 0; ; i++) {
              semaphore_V(consumer);
              semaphore_P(producer);

              printf("Data recieived:%s, sequence:%d/n", shm->buf, shm->seg);

              if (strncmp(shm->buf, "end", 3) == 0)
                     break;
       }

       rm_semaphore(producer);
       rm_semaphore(consumer);

       exit(0);
}

 

server.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>
#include "outshm.h"

#define SHMSZ 27

int main(void) {

       exchage_T *shm, *s;
       int producer, consumer, i;
       char readbuf[BUFSIZE];
       key_t key1 = 123, key2 = 456;

       consumer = open_semaphore_set(key1, 1);
       init_a_semaphore(consumer, 0, 0);

       producer = open_semaphore_set(key2, 1);
       init_a_semaphore(producer, 0, 0);

       shm = (exchange_T*)shminit(ftok("shared", 0));

       for(i = 0; ; i++) {
              printf("Enter some text:");
              fgets(readbuf, BUFSIZE, stdin);
              semaphore_P(consumer);
              shm->seq = i;
              sprintf(shm->buf, "%s", readbuf);
              semaphore_V(producer);
              if(strncmp(readbuf, "end", 3) == 0)
                     break;
       }

       exit(0);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值