1. 程式人生 > >嵌入式Linux併發程式設計,程序間通訊方式,System V IPC物件,ftok(),共享記憶體使用步驟,建立shmget(),對映shmat(),撤銷對映shmdt(),控制shmctl(),注意

嵌入式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物件
[email protected]:~$ 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減一)
[email protected]:~$ 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

[email protected]:~$ cat /proc/sys/kernel/shmmax 
33554432