嵌入式 Linux进程间通信(八)——共享内存

一、共享内存

    共享内存允许两个或更多进程共享给定的内存区,数据不需要在不同进程间进行复制,是最快的进程间通信方式。使用共享内存唯一需要注意的是多个进程之间对给定存储区的同步访问,但共享内存本身没有提供同步机制,通常使用信号量来实现对共享内存访问的同步。

    共享内存编程流程:创建共享内存、映射共享内存、使用共享内存、撤销映射操作、删除共享内存

1、创建共享内存

#include <sys/ipc.h>

#include <sys/shm.h>

 

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

    key:非0整数

        size以字节为单位指定需要共享的内存容量

        shmflg权限标志可以与IPC_CREAT做或操作

        shmget函数成功时返回一个与key相关的共享内存标识符(非负整数)。调用失败返回-1.

2、映射共享内存

#include <sys/types.h>

#include <sys/shm.h>

 

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

    shm_id是由shmget函数返回的共享内存标识。

    shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。

    shm_flg是一组标志位,通常为0

    调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1

3、使用共享内存

    可以使用不带缓存的IO函数对共享内存进行能操作

4、撤销映射共享内存操作

#include <sys/types.h>

#include <sys/shm.h>

 

int shmdt(const void *shmaddr);

    将共享内存从当前进程中分离shmaddrshmat函数返回的地址指针,调用成功时返回0,失败时返回-1

5、删除共享内存

#include <sys/ipc.h>

#include <sys/shm.h>

 

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

    shm_idshmget函数返回的共享内存标识符。

    command是要采取的操作,有三种操作:

    IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。

    IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值

    IPC_RMID:删除共享内存段

    buf是一个结构指针,它指向共享内存模式和访问权限的结构。

    shmid_ds结构至少包括以下成员:

struct shmid_ds  

{  

uid_t shm_perm.uid;  

uid_t shm_perm.gid;  

mode_t shm_perm.mode;  

};  

二、共享内存编程实例

    使用共享内存进行进程间通信程序实例:

shmdata.h文件(定义共享内存的数据结构):

#ifndef SHMDATA_H#define SHMDATA_H #define DATA_SIZE 1024 typedef struct shm{int flag;//非0,可读,0,可写unsigned char data[DATA_SIZE];//数据}share_memory;#endif

shmread.c:

#include 
  #include 
  #include 
  #include 
#include 
  #include 
#include 
#include "shmdata.h" int main(int argc, char **argv){int shmid;void *shm = NULL;share_memory *shmdata;key_t key = ftok("./shmread.c", 'k');shmid = shmget(key, sizeof(share_memory), 0666|IPC_CREAT);if(shmid == -1){fprintf(stderr, "shmget failed.\n");exit(-1);}shm = shmat(shmid, 0, 0);if(shm == (void *)-1){fprintf(stderr, "shmat failed.\n");exit(-1);}fprintf(stdout, "sharememory at 0x%X\n", shm);shmdata = (share_memory *)shm;shmdata->flag = 1;int read = 1;while(read){if(shmdata->flag){printf("share memory data:%s\n", shmdata->data);shmdata->flag = 0;}else{printf("waiting...\n");}sleep(1);}if(shmdt(shm) == -1){fprintf(stderr, "shmdt failed.\n");exit(-1);}if(shmctl(shmid, IPC_RMID, 0) == -1){fprintf(stderr, "shmdt failed.\n");exit(-1);}return 0;}

shmwrite.c

#include 
  #include 
  #include 
  #include 
  #include 
#include 
#include 
#include "shmdata.h" int main(int argc, char **argv){int shmid;void *shm = NULL;share_memory * shmdata;key_t key = ftok("./shmread.c", 'k');shmid = shmget(key, sizeof(share_memory), 0666|IPC_CREAT);char buffer[128] = "hello wolrd";if(shmid == -1){fprintf(stderr, "shmget failed.\n");exit(-1);}shm = shmat(shmid, 0, 0);if(shm == (void *)-1){fprintf(stderr, "shmat failed.\n");exit(-1);}fprintf(stdout, "sharememory at 0x%X\n", shm);shmdata = (share_memory *)shm;int read = 1;while(read){if(shmdata->flag == 0){printf("writing...\n");strncpy(shmdata->data, buffer,sizeof(buffer));shmdata->flag = 1;}else{printf("waiting...\n");}sleep(1);}if(shmdt(shm) == -1){fprintf(stderr, "shmdt failed.\n");exit(-1);}return 0;}