Linux共享內存函數

      網友投稿 860 2025-04-01

      1 共享內存的概念


      共享內存是指多個進程可以把一段內存共同的內存映射到自己的進程空間中,從而實現數據的共享和傳輸,它是存在與內核級別的一種資源,是所有進程間通信中方式最快的一種。

      在shell環境下可以使用ipcs查看當前系統IPC中的狀態,例如當前的電腦中:

      $ ipcs ------ Message Queues -------- key msqid owner perms used-bytes messages ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 2260992 deeplearni 600 524288 2 dest 0x00000000 2490369 deeplearni 600 67108864 2 dest 0x00000000 163842 root 777 7680 2 0x00000000 196611 root 777 8294400 2 0x00000000 229380 root 777 4096 2 0x00000000 262149 root 777 8192 2 0x00000000 294918 root 777 12288 2 ...省略 0x00000000 2064444 root 777 233472 2 0x00000000 2097213 root 777 237568 2 0x00000000 2129982 root 777 241664 2 0x00000000 2162751 root 777 245760 2 0x00000000 2654272 deeplearni 600 524288 2 dest 0x00000000 2687041 deeplearni 600 524288 2 dest 0x00000000 2719810 deeplearni 600 524288 2 dest 0x00000000 2752579 deeplearni 600 524288 2 dest 0x00000000 2981956 deeplearni 600 524288 2 dest 0x00000000 2949189 deeplearni 600 524288 2 dest 0x00000000 3014726 deeplearni 600 67108864 2 dest ------ Semaphore Arrays -------- key semid owner perms nsems

      該命令使用附加參數可單獨查看某一IPC:-m(共享內存),-q(消息隊列),-s(信號量)。

      由于多個進程對同一塊內存區域具有訪問權限,各進程間的同步問題需要解決,可以配合信號量進行控制。

      對于每一個共享內存段,內核會為其維護一個shmid_ds類型的結構體:

      // 摘自所用ubuntu18.04電腦中的/usr/include/i386-linux-gnu/bits/shm.h struct shmid_ds { struct ipc_perm shm_perm; /* operation permission struct */ size_t shm_segsz; /* size of segment in bytes */ __time_t shm_atime; /* time of last shmat() */ #ifndef __x86_64__ unsigned long int __glibc_reserved1; #endif __time_t shm_dtime; /* time of last shmdt() */ #ifndef __x86_64__ unsigned long int __glibc_reserved2; #endif __time_t shm_ctime; /* time of last change by shmctl() */ #ifndef __x86_64__ unsigned long int __glibc_reserved3; #endif __pid_t shm_cpid; /* pid of creator */ __pid_t shm_lpid; /* pid of last shmop */ shmatt_t shm_nattch; /* number of current attaches */ __syscall_ulong_t __glibc_reserved4; __syscall_ulong_t __glibc_reserved5; };

      2 共享內存的相關操作

      2.1 創建/打開共享內存

      創建共享內存需要用到shmget()函數,原型如下:

      #include #include #include int shmget(key_t key, int size, int flag);

      創建成功返回共享內存的ID,出錯返回-1。

      參數key為共享內存的鍵值,參數size為創建共享內存的大小,參數flag為調用函數的操作類型。參數key和參數flag共同決定的shmget()的作用:

      key為IPC_PRIVATE時,創建一個新的共享內存,flag取值無效。

      key不為IPC_PRIVATE,且flag設置了IPC_CREAT位,而沒有設置IPC_EXCL位時,如果key為內核中的已存在的共享內存鍵值,則打開,否則創建一個新的共享內存。

      key不為IPC_PRIVATE,且flag設置了IPC_CREAT和IPC_EXCL位時,則只執行創建共享內存操作。如果key為內核中的已存在的共享內存鍵值,返回EEXIST錯誤。

      2.2 共享內存的附加(映射)

      創建一個共享內存后,某個進程若想使用,需要將此內存區域附加(attach)到自己的進程空間(或稱地址映射),需要用到shmat()函數:

      #include #include #include int *shmat(int shmid, const void *addr, int flag);

      運行成功返回指向共享內存段的地址指針,出錯返回-1。

      參數shmid為共享內存的ID,參數addr和參數flag共同說明要引入的地址值,通常只有2種用法:

      addr為0,表明讓內核來決定第1個可引用的位置

      addr非0,且flag中指定SHM_RND,則此段引入到addr所指向的位置。

      shmat()函數執行成功后,會將shmid的共享內存段的shmid_ds結構的shm_nattch計數器值加1。

      2.3 共享內存的分離

      當進程使用完共享內存后,需要將共享內存從其進程空間中去除(detach),使用shmdt()函數:

      #include #include #include int shmdt(void *addr);

      運行成功返回0,出錯返回-1。

      參數addr是調用shmat()函數的返回值,即共享內存段的地址指針。shmdt()函數執行成功后,shm_nattch計數器值減1。

      2.4 共享內存的控制

      使用shmctl()可以對共享內存段進行多種控制操作,函數原型:

      #include #include #include int shmctl(int shmid, int cmd, struct shmid_s *buf);

      運行成功返回0,出錯返回-1。

      參數shmid為共享內存的ID,參數cmd指明了所要進行的操作,與參數*buf配合使用:

      3 編程示例

      基本步驟:

      生成key,ftok()

      使用key創建/獲得一個共享內存,shmget()

      映射共享內存,得到虛擬地址,shmat()

      使用共享內存,通過地址指針

      移除映射,shmdt()

      銷毀共享內存,shmctl()

      3.1 示例1

      進程1創建共享內存并寫入數據,shm1.c:

      #include #include #include #include #include #include int main() { // generate key key_t key = ftok("./", 200); printf("key=%#x\n", key); // create a share memory int shmid = shmget(key, 8, IPC_CREAT|0666|IPC_EXCL); if(shmid == -1) { perror("shmget failed\n"); exit(1); } printf("shmid=%#x\n", shmid); // map share memory to get the virtual address void *p = shmat(shmid, 0, 0); if((void *)-1 == p) { perror("shmat failed"); exit(2); } // write data to share memory int *pi = p; *pi = 0xaaaaaaaa; *(pi+1) = 0x55555555; // remove the map if(shmdt(p) == -1) { perror("shmdt failed"); exit(3); } // delete the share memory printf("use Enter to destroy the share memory\n"); getchar(); if(shmctl(shmid, IPC_RMID, NULL) == -1) { perror("shmctl"); exit(4); } return 0; }

      進程2讀取共享內存中的內容,shm2.c;

      #include #include #include #include #include #include int main() { // generate key key_t key = ftok("./", 200); printf("key=%#x\n", key); // get the share memory int shmid = shmget(key, 0, 0); if(shmid == -1) { perror("shmget failed\n"); exit(1); } printf("shmid=%#x\n", shmid); // map share memory to get the virtual address void *p = shmat(shmid, 0, 0); if((void *)-1 == p) { perror("shmat failed"); exit(2); } // read: get data from the share memory int x = *((int *)p); int y = *((int *)p+1); printf("x=%#x y=%#x\n", x, y); // remove the map if(shmdt(p) == -1) { perror("shmdt failed"); exit(3); } return 0; }

      編譯運行測試,在一個shell中先運行shm1程序:

      $ ./shm1 key=0xc81102ed shmid=0x2e8047 use Enter to destroy the share memory

      在另一個shell中先運行shm2程序:

      $ ./shm2 key=0xc81102ed shmid=0x2e8047 x=0xaaaaaaaa y=0x55555555

      可以看到通信成功,在第一個shell中按下“Enter”可以銷毀共享內存。

      3.2 示例2

      示例1使用ftok()函數生成的key創建共享內存,本示例使用IPC_PRIVATE參數創建共享內存。

      創建一個共享內存,并輸出其ID號,create_shm.c:

      #include #include #include #include #include #define BUFSZ 4096 int main(void) { int shm_id; shm_id = shmget(IPC_PRIVATE, BUFSZ, 0666); if(shm_id < 0) { printf("shmget failed!\n"); exit(1); } printf("create a shared memory segment successfully: %d\n", shm_id); system("ipcs -m"); exit(0); }

      Linux共享內存及函數

      打開指定ID的共享內存,寫入內容,write_shm.c:

      #include #include #include #include #include #include #include typedef struct { char name[4]; int age; }people; int main(int argc, char **argv) { int shm_id, i; char temp; people *p_map; if(argc != 2) { printf("USAGE:atshm \n"); exit(1); } // get share memory ID from input shm_id = atoi(argv[1]);// str to int // map the share memory to get the virtul address p_map = (people *)shmat(shm_id, NULL, 0); // write temp = 'a'; for(i=0; i<10; i++) { temp+=1; memcpy((*(p_map+i)).name, &temp, 1); (*(p_map+i)).age=20+i; } // remove map if(shmdt(p_map)==-1) perror("detach error!\n"); return 0; }

      打開指定ID的共享內存,讀取內容,read_shm.c:

      #include #include #include #include #include #include typedef struct { char name[4]; int age; }people; int main(int argc, char** argv) { int shm_id, i; people *p_map; if(argc != 2) { printf("USAGC: atshm \n"); exit(1); } // get the share memory ID from input shm_id = atoi(argv[1]);// str to int // map the share memory to get the virtual address p_map = (people*)shmat(shm_id, NULL, 0); // read data for(i=0; i<10; i++) { printf("name:%s ", (*(p_map+i)).name); printf("age %d\n", (*(p_map+i)).age); } // remove the map if(shmdt(p_map)==-1) perror("detach error!\n"); return 0; }

      編譯上述3個程序,首先運行create_shm程序創建一個共享內存:

      $ ./create_shm create a shared memory segment successfully: 3080264 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 2260992 deeplearni 600 524288 2 dest 0x00000000 2490369 deeplearni 600 67108864 2 dest 0x00000000 163842 root 777 7680 2 0x00000000 196611 root 777 8294400 2 0x00000000 229380 root 777 4096 2 ...省略 0x00000000 2031675 root 777 229376 2 0x00000000 2064444 root 777 233472 2 0x00000000 2097213 root 777 237568 2 0x00000000 2129982 root 777 241664 2 0x00000000 2162751 root 777 245760 2 0x00000000 2654272 deeplearni 600 524288 2 dest 0x00000000 2687041 deeplearni 600 524288 2 dest 0x00000000 2719810 deeplearni 600 524288 2 dest 0x00000000 2752579 deeplearni 600 524288 2 dest 0x00000000 2981956 deeplearni 600 524288 2 dest 0x00000000 2949189 deeplearni 600 524288 2 dest 0x00000000 3014726 deeplearni 600 67108864 2 dest 0xc81102ed 3047495 deeplearni 666 8 0 0x00000000 3080264 deeplearni 666 4096 0

      可以看到程序創建了一個shmid為3080264的共享內存,然后可以運行write_shm程序,需要將ID號作為參數:

      $ ./write_shm 3080264

      雖然沒有輸出,但程序已將內容寫入共享內存,并且共享內存沒有被刪除,可以運行read_shm程序讀取共享內存中的內容:

      $ ./read_shm 3080264 name:b age 20 name:c age 21 name:d age 22 name:e age 23 name:f age 24 name:g age 25 name:h age 26 name:i age 27 name:j age 28 name:k age 29

      可以看到,程序讀取到了共享內存中存儲的10個字符。

      另外,無用的共享內存也可以通過命令的方式收到刪除,使用ipcrm -m 共享內存id的形式,如:

      $ ipcrm -m 3080264

      此時再用ipcs -m命令查看,已經沒有shmid為3080264的共享內存。

      Linux 任務調度

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:excel中hlookup函數的使用方法
      下一篇:excel中繁體轉簡體選項不見了怎么辦(excel沒有簡體轉繁體)
      相關文章
      亚洲国产一成人久久精品| 亚洲综合AV在线在线播放| 久久精品九九亚洲精品天堂| 亚洲AV日韩精品一区二区三区| 亚洲日韩AV一区二区三区中文| 久久精品国产亚洲αv忘忧草| 亚洲精品福利网站| 亚洲美女免费视频| 亚洲福利秒拍一区二区| 中文字幕亚洲综合久久2| 日韩亚洲AV无码一区二区不卡| 亚洲AV永久青草无码精品| 久久精品国产亚洲AV麻豆王友容| 亚洲国产精品无码一线岛国| 亚洲国产精品特色大片观看完整版| 亚洲乱码一区二区三区在线观看| 亚洲中文字幕日产乱码高清app| 亚洲日韩v无码中文字幕| 亚洲国产成人一区二区三区| 亚洲国产精品乱码一区二区| 亚洲国产精品久久66| 99ri精品国产亚洲| 亚洲成a人片77777群色| 亚洲午夜国产精品| 亚洲自偷自偷在线成人网站传媒| 亚洲欧美自偷自拍另类视| 亚洲成av人片天堂网无码】| 国产精品亚洲片在线花蝴蝶| 亚洲免费视频一区二区三区| 久久亚洲av无码精品浪潮| 亚洲国产综合无码一区| 午夜影视日本亚洲欧洲精品一区| 久久精品蜜芽亚洲国产AV | 亚洲人妖女同在线播放| 色在线亚洲视频www| 亚洲熟伦熟女专区hd高清| 久久久久久久久无码精品亚洲日韩| 亚洲AV日韩精品一区二区三区 | 亚洲国产天堂久久久久久| 国产亚洲精品久久久久秋霞| 亚洲成AV人片在线观看无|