嵌入式Linux并发程序设计,进程间通信方式,System V IPC对象,ftok(),共享内存使用步骤,创建shmget(),映射shmat(),撤销映射shmdt(),控制shmctl(),注意

1,System V IPC

  1. IPC 对象包含: 共享内存、消息队列和信号灯集
  2. 每个IPC对象有唯一的ID(IPC对象创建的时候由系统分配的一个数字,只有创建IPC对象的进程可以获得ID,别的进程不知道这个ID号)
  3. IPC对象创建后一直存在,直到被显式地删除
  4. 每个IPC对象有一个关联的KEY(可以看成IPC对象的一个属性,通过KEY值,可以使不同的进程能够打开同一个IPC对象。创建IPC对象的进程把KEY值和IPC对象关联)
  5. ipcs / ipcrm
    ·ipcs查看System V的IPC对象(显示当前系统中所有的IPC对象)
    ·iprm删除System V的IPC对象
linux@linux:~$ ipcs

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 1769472    linux      600        524288     2          dest         
0x00000000 327681     linux      600        524288     2          dest         
0x00000000 425986     linux      600        524288     2          dest         
0x00000000 819203     linux      600        524288     2          dest         
0x00000000 1376260    linux      600        33554432   2          dest         
0x00000000 917509     linux      600        524288     2          dest         
0x00000000 950278     linux      600        16777216   2                       
0x00000000 1277959    linux      600        524288     2          dest         
0x00000000 1146888    linux      600        524288     2          dest         
0x00000000 1900553    linux      600        524288     2          dest         
0x00000000 1998858    linux      600        524288     2          dest         
0x00000000 1802251    linux      600        2097152    2          dest         

------ Semaphore Arrays --------
key        semid      owner      perms      nsems     

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    

  • KEY值为0,表示私有的IPC对象
ipcrm [ -M key | -m id | -Q key | -q id | -S key | -s id ] ...
  1. M/m 对应共享内存
  2. Q/q 对应消息队列
  3. S/s 对应信号灯集

2,使用IPC对象的大致流程

在这里插入图片描述

  1. 进程创建IPC对象之前先指定一个KEY,KEY的值可以为0(宏IPC_PRIVATE的值为0),为0表示这是一个私有对象,不为0表示这个对象会被多个进程访问
  2. KEY值还可以通过函数ftok()创建(避免指定的KEY值会与系统中已有的KEY值冲突)
  3. 根据KEY值去创建IPC对象

3,生成KEY值ftok()

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *path, int proj_id);

  1. 成功时返回合法的key值,失败时返回EOF
  2. path 存在且可访问的文件的路径(ftok()生成的KEY值实际上path所指的文件的i节点的编号)
  3. proj_id 用于生成key的数字,不能为0(i节点的编号和proj_id的低8为进行移位,拼成一个新的数字)

ftok示例

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>  
#include <sys/ipc.h>
#include <unistd.h>

int main(int argc, char *argv[]) 
{
   key_t key;

   if ((key = ftok(., ‘a’)) == -1) 
   {
      perror(“key”);
      exit(-1);
   }   
   ……
  • 每个进程必须生成相同的KEY,才能通过相同的KEY,找到相同的IPC对象(每个进程都需要调用ftok()函数,且参数必须一致,参数一致才能生成相同的KEY)

4,共享内存

  1. 共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝
  2. 共享内存在内核空间创建,可被进程映射到用户空间访问,使用灵活
  3. 由于多个进程可同时访问共享内存,因此需要同步和互斥机制配合使用

4.1,共享内存使用步骤

  1. 创建/打开共享内存
  2. 映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
  3. 读写共享内存
  4. 撤销共享内存映射
  5. 删除共享内存对象

4.2,共享内存创建 shmget()

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, int size, int shmflg);

  1. 成功时返回共享内存的id,失败时返回EOF
  2. key 和共享内存关联的key,IPC_PRIVATE 或 ftok生成
  3. size指定共享内存的大小,以字节为单位
  4. shmflg 共享内存标志位 IPC_CREAT|0666(是否新建,以及对共享内存的读写权限)

4.2.1,共享内存创建shmget()示例

示例一:创建一个私有的共享内存,大小为512字节,权限为0666

  int shmid;
  if ((shmid = shmget(IPC_PRIVATE, 512, 0666)) < 0) 
  {
     perror(“shmget”);
     exit(-1);
  }
  • 私有的共享内存一定是新建的,所以不需要加 IPC_CREAT标志

示例二:创建/打开一个和key关联的共享内存,大小为1024字节,权限为0666

key_t key;
int shmid;

if ((key = ftok(., ‘m’)) == -1) 
{
	perror(“ftok”);
	exit(-1);
}
if ((shmid = shmget(key, 1024, IPC_CREAT|0666)) < 0) 
{
	perror(“shmget”);
	exit(-1);
}
  • 指定了IPC_CREAT标志,执行shmget()函数的时候,系统会检查,如果和key关联的共享内存对象不存在则创建一个,并把key值和对象关联;如果已经存在,直接返回对象ID,并打开

4.3,共享内存映射 shmat()

#include <sys/ipc.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);

  1. 成功时返回映射后的地址,失败时返回(void *)-1
  2. shmid 要映射的共享内存id
  3. shmaddr 映射后的地址, NULL表示由系统自动映射
  4. shmflg 标志位 0表示可读写;SHM_RDONLY表示只读

4.4,共享内存读写—示例

例如:在共享内存中存放键盘输入的字符串

char *addr;
int  shmid;
……
if ((addr = (char *)shmat(shmid, NULL, 0)) == (char *)-1) 
{
	perror(“shmat”);
	exit(-1);
}
fgets(addr, N, stdin);
……  
  • 通过指针访问共享内存,指针类型取决于共享内存中存放的数据类型

4.5,共享内存撤销映射 shmdt()

#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(void *shmaddr);

  1. 成功时返回0,失败时返回EOF
  2. 不使用共享内存时应撤销映射
  3. 进程结束时自动撤销
  4. shmaddr 映射后的地址

4.6,共享内存控制 shmctl()

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

  1. 成功时返回0,失败时返回EOF
  2. shmid 要操作的共享内存的id
  3. cmd 要执行的操作 IPC_STAT(获取当前共享内存的shmid_ds结构并保存在buf中) IPC_SET(使用buf中的值设置当前共享内存的shmid_ds结构) IPC_RMID(删除当前共享内存,第三个参数传NULL)
  4. buf 保存或设置共享内存属性的地址
  5. shmid_ds结构 ,共享内存的属性,包括:大小、跟它关联的key值、权限、创建者用户ID等

4.7,共享内存 - 注意事项

  1. 每块共享内存大小有限制
    ·ipcs -l(查看当前系统中关于三类IPC对象的设置)
    ·cat /proc/sys/kernel/shmmax(查看当前系统中关于共享内存最大大小的设定)
  2. 修改共享内存大小
    ·sysctl -w kernel.shmmax=134217728
    ·echo 134217728 >/proc/sys/kernel/shmmax
  3. 共享内存删除的时间点(最后一个进程负责删除共享内存)
    ·shmctl(shmid, IPC_RMID, NULL) 添加删除标记
    ·nattach 变成0时真正删除(nattach记录了有几个进程映射了共享内存,调用shmat()时nattach加一,调用shmdt()nattach减一)
linux@linux:~$ ipcs -l

------ Shared Memory Limits --------
max number of segments = 4096
max seg size (kbytes) = 32768
max total shared memory (kbytes) = 8388608
min seg size (bytes) = 1

------ Semaphore Limits --------
max number of arrays = 128
max semaphores per array = 250
max semaphores system wide = 32000
max ops per semop call = 32
semaphore max value = 32767

------ Messages Limits --------
max queues system wide = 1737
max size of message (bytes) = 8192
default max size of queue (bytes) = 16384

linux@linux:~$ cat /proc/sys/kernel/shmmax 
33554432

猜你喜欢

转载自blog.csdn.net/m0_37542524/article/details/84000021