自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux進(jìn)程間通信——使用共享內(nèi)存

系統(tǒng) Linux
共享內(nèi)存就是允許兩個(gè)不相關(guān)的進(jìn)程訪問(wèn)同一個(gè)邏輯內(nèi)存。共享內(nèi)存是在兩個(gè)正在運(yùn)行的進(jìn)程之間共享和傳遞數(shù)據(jù)的一種非常有效的方式。不同進(jìn)程之間共享的內(nèi)存通常安排為同一段物理內(nèi)存。

Linux進(jìn)程間通信——使用共享內(nèi)存

下面將講解進(jìn)程間通信的另一種方式,使用共享內(nèi)存。 

一、什么是共享內(nèi)存

顧名思義,共享內(nèi)存就是允許兩個(gè)不相關(guān)的進(jìn)程訪問(wèn)同一個(gè)邏輯內(nèi)存。共享內(nèi)存是在兩個(gè)正在運(yùn)行的進(jìn)程之間共享和傳遞數(shù)據(jù)的一種非常有效的方式。不同進(jìn)程之間共享的內(nèi)存通常安排為同一段物理內(nèi)存。進(jìn)程可以將同一段共享內(nèi)存連接到它們自己的地址空間中,所有進(jìn)程都可以訪問(wèn)共享內(nèi)存中的地址,就好像它們是由用C語(yǔ)言函數(shù)malloc分配的內(nèi)存一樣。而如果某個(gè)進(jìn)程向共享內(nèi)存寫(xiě)入數(shù)據(jù),所做的改動(dòng)將立即影響到可以訪問(wèn)同一段共享內(nèi)存的任何其他進(jìn)程。 

特別提醒:共享內(nèi)存并未提供同步機(jī)制,也就是說(shuō),在***個(gè)進(jìn)程結(jié)束對(duì)共享內(nèi)存的寫(xiě)操作之前,并無(wú)自動(dòng)機(jī)制可以阻止第二個(gè)進(jìn)程開(kāi)始對(duì)它進(jìn)行讀取。所以我們通常需要用其他的機(jī)制來(lái)同步對(duì)共享內(nèi)存的訪問(wèn),例如前面說(shuō)到的信號(hào)量。有關(guān)信號(hào)量的更多內(nèi)容,可以查閱我的另一篇文章:Linux進(jìn)程間通信——使用信號(hào)量 

二、共享內(nèi)存的使得

與信號(hào)量一樣,在Linux中也提供了一組函數(shù)接口用于使用共享內(nèi)存,而且使用共享共存的接口還與信號(hào)量的非常相似,而且比使用信號(hào)量的接口來(lái)得簡(jiǎn)單。它們聲明在頭文件 sys/shm.h中。 

1、shmget函數(shù)

該函數(shù)用來(lái)創(chuàng)建共享內(nèi)存,它的原型為: 

  1. [cpp] view plain copy  
  2.  
  3. int shmget(key_t key, size_t sizeint shmflg);   

***個(gè)參數(shù),與信號(hào)量的semget函數(shù)一樣,程序需要提供一個(gè)參數(shù)key(非0整數(shù)),它有效地為共享內(nèi)存段命名,shmget函數(shù)成功時(shí)返回一個(gè)與key相關(guān)的共享內(nèi)存標(biāo)識(shí)符(非負(fù)整數(shù)),用于后續(xù)的共享內(nèi)存函數(shù)。調(diào)用失敗返回-1. 

不相關(guān)的進(jìn)程可以通過(guò)該函數(shù)的返回值訪問(wèn)同一共享內(nèi)存,它代表程序可能要使用的某個(gè)資源,程序?qū)λ泄蚕韮?nèi)存的訪問(wèn)都是間接的,程序先通過(guò)調(diào)用shmget函數(shù)并提供一個(gè)鍵,再由系統(tǒng)生成一個(gè)相應(yīng)的共享內(nèi)存標(biāo)識(shí)符(shmget函數(shù)的返回值),只有shmget函數(shù)才直接使用信號(hào)量鍵,所有其他的信號(hào)量函數(shù)使用由semget函數(shù)返回的信號(hào)量標(biāo)識(shí)符。 

第二個(gè)參數(shù),size以字節(jié)為單位指定需要共享的內(nèi)存容量 

第三個(gè)參數(shù),shmflg是權(quán)限標(biāo)志,它的作用與open函數(shù)的mode參數(shù)一樣,如果要想在key標(biāo)識(shí)的共享內(nèi)存不存在時(shí),創(chuàng)建它的話,可以與IPC_CREAT做或操作。共享內(nèi)存的權(quán)限標(biāo)志與文件的讀寫(xiě)權(quán)限一樣,舉例來(lái)說(shuō),0644,它表示允許一個(gè)進(jìn)程創(chuàng)建的共享內(nèi)存被內(nèi)存創(chuàng)建者所擁有的進(jìn)程向共享內(nèi)存讀取和寫(xiě)入數(shù)據(jù),同時(shí)其他用戶創(chuàng)建的進(jìn)程只能讀取共享內(nèi)存。 

2、shmat函數(shù)

***次創(chuàng)建完共享內(nèi)存時(shí),它還不能被任何進(jìn)程訪問(wèn),shmat函數(shù)的作用就是用來(lái)啟動(dòng)對(duì)該共享內(nèi)存的訪問(wèn),并把共享內(nèi)存連接到當(dāng)前進(jìn)程的地址空間。它的原型如下: 

  1. [cpp] view plain copy  
  2.  
  3. void *shmat(int shm_id, const void *shm_addr, int shmflg);    

***個(gè)參數(shù),shm_id是由shmget函數(shù)返回的共享內(nèi)存標(biāo)識(shí)。

第二個(gè)參數(shù),shm_addr指定共享內(nèi)存連接到當(dāng)前進(jìn)程中的地址位置,通常為空,表示讓系統(tǒng)來(lái)選擇共享內(nèi)存的地址。

第三個(gè)參數(shù),shm_flg是一組標(biāo)志位,通常為0。 

調(diào)用成功時(shí)返回一個(gè)指向共享內(nèi)存***個(gè)字節(jié)的指針,如果調(diào)用失敗返回-1. 

3、shmdt函數(shù)

該函數(shù)用于將共享內(nèi)存從當(dāng)前進(jìn)程中分離。注意,將共享內(nèi)存分離并不是刪除它,只是使該共享內(nèi)存對(duì)當(dāng)前進(jìn)程不再可用。它的原型如下: 

  1. [cpp] view plain copy  
  2.  
  3. int shmdt(const void *shmaddr);    

參數(shù)shmaddr是shmat函數(shù)返回的地址指針,調(diào)用成功時(shí)返回0,失敗時(shí)返回-1. 

4、shmctl函數(shù)

與信號(hào)量的semctl函數(shù)一樣,用來(lái)控制共享內(nèi)存,它的原型如下: 

  1. [cpp] view plain copy  
  2.  
  3. int shmctl(int shm_id, int command, struct shmid_ds *buf);    

***個(gè)參數(shù),shm_id是shmget函數(shù)返回的共享內(nèi)存標(biāo)識(shí)符。 

第二個(gè)參數(shù),command是要采取的操作,它可以取下面的三個(gè)值 :

  • IPC_STAT:把shmid_ds結(jié)構(gòu)中的數(shù)據(jù)設(shè)置為共享內(nèi)存的當(dāng)前關(guān)聯(lián)值,即用共享內(nèi)存的當(dāng)前關(guān)聯(lián)值覆蓋shmid_ds的值。
  • IPC_SET:如果進(jìn)程有足夠的權(quán)限,就把共享內(nèi)存的當(dāng)前關(guān)聯(lián)值設(shè)置為shmid_ds結(jié)構(gòu)中給出的值
  • IPC_RMID:刪除共享內(nèi)存段 

第三個(gè)參數(shù),buf是一個(gè)結(jié)構(gòu)指針,它指向共享內(nèi)存模式和訪問(wèn)權(quán)限的結(jié)構(gòu)。

shmid_ds結(jié)構(gòu)至少包括以下成員:  

  1. [cpp] view plain copy  
  2.  
  3. struct shmid_ds   
  4.  
  5. {   
  6.  
  7.     uid_t shm_perm.uid;   
  8.  
  9.     uid_t shm_perm.gid;   
  10.  
  11.     mode_t shm_perm.mode;   
  12.  
  13. };    

三、使用共享內(nèi)存進(jìn)行進(jìn)程間通信

說(shuō)了這么多,又到了實(shí)戰(zhàn)的時(shí)候了。下面就以兩個(gè)不相關(guān)的進(jìn)程來(lái)說(shuō)明進(jìn)程間如何通過(guò)共享內(nèi)存來(lái)進(jìn)行通信。其中一個(gè)文件shmread.c創(chuàng)建共享內(nèi)存,并讀取其中的信息,另一個(gè)文件shmwrite.c向共享內(nèi)存中寫(xiě)入數(shù)據(jù)。為了方便操作和數(shù)據(jù)結(jié)構(gòu)的統(tǒng)一,為這兩個(gè)文件定義了相同的數(shù)據(jù)結(jié)構(gòu),定義在文件shmdata.c中。結(jié)構(gòu)shared_use_st中的written作為一個(gè)可讀或可寫(xiě)的標(biāo)志,非0:表示可讀,0表示可寫(xiě),text則是內(nèi)存中的文件。 

shmdata.h的源代碼如下: 

  1. [cpp] view plain copy  
  2.  
  3. #ifndef _SHMDATA_H_HEADER   
  4.  
  5. #define _SHMDATA_H_HEADER     
  6.  
  7. #define TEXT_SZ 2048     
  8.  
  9. struct shared_use_st   
  10.  
  11. {   
  12.  
  13.     int written;//作為一個(gè)標(biāo)志,非0:表示可讀,0表示可寫(xiě)   
  14.  
  15.     char text[TEXT_SZ];//記錄寫(xiě)入和讀取的文本   
  16.  
  17. };     
  18.  
  19. #endif    

源文件shmread.c的源代碼如下:  

  1. [cpp] view plain copy  
  2.  
  3. #include <unistd.h>   
  4.  
  5. #include <stdlib.h>   
  6.  
  7. #include <stdio.h>   
  8.  
  9. #include <sys/shm.h>   
  10.  
  11. #include "shmdata.h"     
  12.  
  13. int main()   
  14.  
  15. {   
  16.  
  17.     int running = 1;//程序是否繼續(xù)運(yùn)行的標(biāo)志   
  18.  
  19.     void *shm = NULL;//分配的共享內(nèi)存的原始首地址   
  20.  
  21.     struct shared_use_st *shared;//指向shm   
  22.  
  23.     int shmid;//共享內(nèi)存標(biāo)識(shí)符   
  24.  
  25.     //創(chuàng)建共享內(nèi)存   
  26.  
  27.     shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);   
  28.  
  29.     if(shmid == -1)   
  30.  
  31.     {   
  32.  
  33.         fprintf(stderr, "shmget failed\n");   
  34.  
  35.         exit(EXIT_FAILURE);   
  36.  
  37.     }   
  38.  
  39.     //將共享內(nèi)存連接到當(dāng)前進(jìn)程的地址空間   
  40.  
  41.     shm = shmat(shmid, 0, 0);   
  42.  
  43.     if(shm == (void*)-1)   
  44.  
  45.     {   
  46.  
  47.         fprintf(stderr, "shmat failed\n");   
  48.  
  49.         exit(EXIT_FAILURE);   
  50.  
  51.     }   
  52.  
  53.     printf("\nMemory attached at %X\n", (int)shm);   
  54.  
  55.     //設(shè)置共享內(nèi)存   
  56.  
  57.     shared = (struct shared_use_st*)shm;   
  58.  
  59.     shared->written = 0;   
  60.  
  61.     while(running)//讀取共享內(nèi)存中的數(shù)據(jù)   
  62.  
  63.     {   
  64.  
  65.         //沒(méi)有進(jìn)程向共享內(nèi)存定數(shù)據(jù)有數(shù)據(jù)可讀取   
  66.  
  67.         if(shared->written != 0)   
  68.  
  69.         {   
  70.  
  71.             printf("You wrote: %s", shared->text);   
  72.  
  73.             sleep(rand() % 3);   
  74.  
  75.             //讀取完數(shù)據(jù),設(shè)置written使共享內(nèi)存段可寫(xiě)   
  76.  
  77.             shared->written = 0;   
  78.  
  79.             //輸入了end,退出循環(huán)(程序)   
  80.  
  81.             if(strncmp(shared->text, "end", 3) == 0)   
  82.  
  83.                 running = 0;   
  84.  
  85.         }   
  86.  
  87.         else//有其他進(jìn)程在寫(xiě)數(shù)據(jù),不能讀取數(shù)據(jù)   
  88.  
  89.             sleep(1);   
  90.  
  91.     }   
  92.  
  93.     //把共享內(nèi)存從當(dāng)前進(jìn)程中分離   
  94.  
  95.     if(shmdt(shm) == -1)   
  96.  
  97.     {   
  98.  
  99.         fprintf(stderr, "shmdt failed\n");   
  100.  
  101.         exit(EXIT_FAILURE);   
  102.  
  103.     }   
  104.  
  105.     //刪除共享內(nèi)存   
  106.  
  107.     if(shmctl(shmid, IPC_RMID, 0) == -1)   
  108.  
  109.     {   
  110.  
  111.         fprintf(stderr, "shmctl(IPC_RMID) failed\n");   
  112.  
  113.         exit(EXIT_FAILURE);   
  114.  
  115.     }   
  116.  
  117.     exit(EXIT_SUCCESS);   
  118.  
  119. }    

源文件shmwrite.c的源代碼如下: 

  1. [cpp] view plain copy  
  2.  
  3. #include <unistd.h>   
  4.  
  5. #include <stdlib.h>   
  6.  
  7. #include <stdio.h>   
  8.  
  9. #include <string.h>   
  10.  
  11. #include <sys/shm.h>   
  12.  
  13. #include "shmdata.h"     
  14.  
  15. int main()   
  16.  
  17. {   
  18.  
  19.     int running = 1;   
  20.  
  21.     void *shm = NULL;   
  22.  
  23.     struct shared_use_st *shared = NULL;   
  24.  
  25.     char buffer[BUFSIZ + 1];//用于保存輸入的文本   
  26.  
  27.     int shmid;   
  28.  
  29.     //創(chuàng)建共享內(nèi)存   
  30.  
  31.     shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);   
  32.  
  33.     if(shmid == -1)   
  34.  
  35.     {   
  36.  
  37.         fprintf(stderr, "shmget failed\n");   
  38.  
  39.         exit(EXIT_FAILURE);   
  40.  
  41.     }   
  42.  
  43.     //將共享內(nèi)存連接到當(dāng)前進(jìn)程的地址空間   
  44.  
  45.     shm = shmat(shmid, (void*)0, 0);   
  46.  
  47.     if(shm == (void*)-1)   
  48.  
  49.     {   
  50.  
  51.         fprintf(stderr, "shmat failed\n");   
  52.  
  53.         exit(EXIT_FAILURE);   
  54.  
  55.     }   
  56.  
  57.     printf("Memory attached at %X\n", (int)shm);   
  58.  
  59.     //設(shè)置共享內(nèi)存   
  60.  
  61.     shared = (struct shared_use_st*)shm;   
  62.  
  63.     while(running)//向共享內(nèi)存中寫(xiě)數(shù)據(jù)   
  64.  
  65.     {   
  66.  
  67.         //數(shù)據(jù)還沒(méi)有被讀取,則等待數(shù)據(jù)被讀取,不能向共享內(nèi)存中寫(xiě)入文本   
  68.  
  69.         while(shared->written == 1)   
  70.  
  71.         {   
  72.  
  73.             sleep(1);   
  74.  
  75.             printf("Waiting...\n");   
  76.  
  77.         }   
  78.  
  79.         //向共享內(nèi)存中寫(xiě)入數(shù)據(jù)   
  80.  
  81.         printf("Enter some text: ");   
  82.  
  83.         fgets(buffer, BUFSIZ, stdin);   
  84.  
  85.         strncpy(shared->text, buffer, TEXT_SZ);   
  86.  
  87.         //寫(xiě)完數(shù)據(jù),設(shè)置written使共享內(nèi)存段可讀   
  88.  
  89.         shared->written = 1;   
  90.  
  91.         //輸入了end,退出循環(huán)(程序)   
  92.  
  93.         if(strncmp(buffer, "end", 3) == 0)   
  94.  
  95.             running = 0;   
  96.  
  97.     }   
  98.  
  99.     //把共享內(nèi)存從當(dāng)前進(jìn)程中分離   
  100.  
  101.     if(shmdt(shm) == -1)   
  102.  
  103.     {   
  104.  
  105.         fprintf(stderr, "shmdt failed\n");   
  106.  
  107.         exit(EXIT_FAILURE);   
  108.  
  109.     }   
  110.  
  111.     sleep(2);   
  112.  
  113.     exit(EXIT_SUCCESS);   
  114.  
  115.  

再來(lái)看看運(yùn)行的結(jié)果: 

分析:

1、程序shmread創(chuàng)建共享內(nèi)存,然后將它連接到自己的地址空間。在共享內(nèi)存的開(kāi)始處使用了一個(gè)結(jié)構(gòu)struct_use_st。該結(jié)構(gòu)中有個(gè)標(biāo)志written,當(dāng)共享內(nèi)存中有其他進(jìn)程向它寫(xiě)入數(shù)據(jù)時(shí),共享內(nèi)存中的written被設(shè)置為0,程序等待。當(dāng)它不為0時(shí),表示沒(méi)有進(jìn)程對(duì)共享內(nèi)存寫(xiě)入數(shù)據(jù),程序就從共享內(nèi)存中讀取數(shù)據(jù)并輸出,然后重置設(shè)置共享內(nèi)存中的written為0,即讓其可被shmwrite進(jìn)程寫(xiě)入數(shù)據(jù)。 

2、程序shmwrite取得共享內(nèi)存并連接到自己的地址空間中。檢查共享內(nèi)存中的written,是否為0,若不是,表示共享內(nèi)存中的數(shù)據(jù)還沒(méi)有被完,則等待其他進(jìn)程讀取完成,并提示用戶等待。若共享內(nèi)存的written為0,表示沒(méi)有其他進(jìn)程對(duì)共享內(nèi)存進(jìn)行讀取,則提示用戶輸入文本,并再次設(shè)置共享內(nèi)存中的written為1,表示寫(xiě)完成,其他進(jìn)程可對(duì)共享內(nèi)存進(jìn)行讀操作。 

四、關(guān)于前面的例子的安全性討論

這個(gè)程序是不安全的,當(dāng)有多個(gè)程序同時(shí)向共享內(nèi)存中讀寫(xiě)數(shù)據(jù)時(shí),問(wèn)題就會(huì)出現(xiàn)??赡苣銜?huì)認(rèn)為,可以改變一下written的使用方式,例如,只有當(dāng)written為0時(shí)進(jìn)程才可以向共享內(nèi)存寫(xiě)入數(shù)據(jù),而當(dāng)一個(gè)進(jìn)程只有在written不為0時(shí)才能對(duì)其進(jìn)行讀取,同時(shí)把written進(jìn)行加1操作,讀取完后進(jìn)行減1操作。這就有點(diǎn)像文件鎖中的讀寫(xiě)鎖的功能。咋看之下,它似乎能行得通。但是這都不是原子操作,所以這種做法是行不能的。試想當(dāng)written為0時(shí),如果有兩個(gè)進(jìn)程同時(shí)訪問(wèn)共享內(nèi)存,它們就會(huì)發(fā)現(xiàn)written為0,于是兩個(gè)進(jìn)程都對(duì)其進(jìn)行寫(xiě)操作,顯然不行。當(dāng)written為1時(shí),有兩個(gè)進(jìn)程同時(shí)對(duì)共享內(nèi)存進(jìn)行讀操作時(shí)也是如些,當(dāng)這兩個(gè)進(jìn)程都讀取完是,written就變成了-1。  

要想讓程序安全地執(zhí)行,就要有一種進(jìn)程同步的進(jìn)制,保證在進(jìn)入臨界區(qū)的操作是原子操作。例如,可以使用前面所講的信號(hào)量來(lái)進(jìn)行進(jìn)程的同步。因?yàn)樾盘?hào)量的操作都是原子性的。 

五、使用共享內(nèi)存的優(yōu)缺點(diǎn)

1、優(yōu)點(diǎn):我們可以看到使用共享內(nèi)存進(jìn)行進(jìn)程間的通信真的是非常方便,而且函數(shù)的接口也簡(jiǎn)單,數(shù)據(jù)的共享還使進(jìn)程間的數(shù)據(jù)不用傳送,而是直接訪問(wèn)內(nèi)存,也加快了程序的效率。同時(shí),它也不像匿名管道那樣要求通信的進(jìn)程有一定的父子關(guān)系。 

2、缺點(diǎn):共享內(nèi)存沒(méi)有提供同步的機(jī)制,這使得我們?cè)谑褂霉蚕韮?nèi)存進(jìn)行進(jìn)程間通信時(shí),往往要借助其他的手段來(lái)進(jìn)行進(jìn)程間的同步工作。 

責(zé)任編輯:龐桂玉 來(lái)源: 嵌入式Linux中文站
相關(guān)推薦

2019-05-08 11:10:05

Linux進(jìn)程語(yǔ)言

2025-04-27 03:22:00

2017-06-19 13:36:12

Linux進(jìn)程消息隊(duì)列

2010-01-05 10:00:48

Linux進(jìn)程間通信

2013-03-28 13:14:45

AIDL進(jìn)程間通信Android使用AI

2025-05-13 07:10:31

2017-08-06 00:05:18

進(jìn)程通信開(kāi)發(fā)

2019-05-13 10:00:41

Linux進(jìn)程間通信命令

2018-05-30 13:58:02

Linux進(jìn)程通信

2020-11-18 09:06:04

Python

2020-11-04 07:17:42

Nodejs通信進(jìn)程

2011-06-22 17:09:50

QT 進(jìn)程 通信

2024-01-03 10:17:51

Linux通信

2019-06-04 09:00:00

Linux進(jìn)程進(jìn)程間通信

2019-11-08 14:47:49

TCPIP網(wǎng)絡(luò)

2020-12-14 08:43:56

線程進(jìn)程資源

2011-06-24 14:01:34

Qt QCOP 協(xié)議

2013-11-26 16:05:24

Linux共享內(nèi)存

2016-11-28 14:11:24

ANDROID BIN通信架構(gòu)

2019-11-27 10:36:11

進(jìn)程通信IPC
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)