• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運(yùn)轉(zhuǎn),開(kāi)心的工作
            簡(jiǎn)單、開(kāi)放、平等的公司文化;尊重個(gè)性、自由與個(gè)人價(jià)值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
            共享內(nèi)存區(qū)域是被多個(gè)進(jìn)程共享的一部分物理內(nèi)存。如果多個(gè)進(jìn)程都把該內(nèi)存區(qū)域映射到自己的虛擬地址空間,則這些進(jìn)程就都可以直接訪問(wèn)該共享內(nèi)存區(qū)域,從而可以通過(guò)該區(qū)域進(jìn)行通信。共享內(nèi)存是進(jìn)程間共享數(shù)據(jù)的一種最快的方法,一個(gè)進(jìn)程向共享內(nèi)存區(qū)域?qū)懭肓藬?shù)據(jù),共享這個(gè)內(nèi)存區(qū)域的所有進(jìn)程就可以立刻看到其中的內(nèi)容。這塊共享虛擬內(nèi)存的頁(yè)面,出現(xiàn)在每一個(gè)共享該頁(yè)面的進(jìn)程的頁(yè)表中。但是它不需要在所有進(jìn)程的虛擬內(nèi)存中都有相同的虛擬地址。?
            圖 共享內(nèi)存映射圖??
            ?????????????????????????Linux?<wbr>進(jìn)程間通信?<wbr>-?<wbr>共享內(nèi)存shmget方式

            ?????????象所有的 System V IPC對(duì)象一樣,對(duì)于共享內(nèi)存對(duì)象的獲取是由key控制。內(nèi)存共享之后,對(duì)進(jìn)程如何使用這塊內(nèi)存就不再做檢查。它們必須依賴于其它機(jī)制,比如System V的信號(hào)燈來(lái)同步對(duì)于共享內(nèi)存區(qū)域的訪問(wèn)(信號(hào)燈如何控制對(duì)臨界代碼的訪問(wèn)另起一篇說(shuō)話)。
            ?
            ????????每一個(gè)新創(chuàng)建的共享內(nèi)存對(duì)象都用一個(gè)shmid_kernel數(shù)據(jù)結(jié)構(gòu)來(lái)表達(dá)。系統(tǒng)中所有的shmid_kernel數(shù)據(jù)結(jié)構(gòu)都保存在shm_segs向量表中,該向量表的每一個(gè)元素都是一個(gè)指向shmid_kernel數(shù)據(jù)結(jié)構(gòu)的指針。
            shm_segs向量表的定義如下:
            struct shmid_kernel *shm_segs[SHMMNI];

            ?
            ??? SHMMNI為128,表示系統(tǒng)中最多可以有128個(gè)共享內(nèi)存對(duì)象。
            ?
            ???數(shù)據(jù)結(jié)構(gòu)shmid_kernel的定義如下:
            ????struct shmid_kernel
            ????{????
            ????????struct shmid_ds u;????????
            ????????unsigned long shm_npages;?
            ????????unsigned long *shm_pages;? ?
            ????????struct vm_area_struct *attaches;?
            ????};

            ?
            ??? 其中:
            ????shm_pages代表該共享內(nèi)存對(duì)象的所占據(jù)的內(nèi)存頁(yè)面數(shù)組,數(shù)組里面的每個(gè)元素當(dāng)然是每個(gè)內(nèi)存頁(yè)面的起始地址.
            ??? shm_npages則是該共享內(nèi)存對(duì)象占用內(nèi)存頁(yè)面的個(gè)數(shù),以頁(yè)為單位。這個(gè)數(shù)量當(dāng)然涵蓋了申請(qǐng)空間的最小整數(shù)倍.
            ????(A new shared memory segment,? with size? equal to the value of size rounded up to a multiple of PAGE_SIZE)
            ??? shmid_ds是一個(gè)數(shù)據(jù)結(jié)構(gòu),它描述了這個(gè)共享內(nèi)存區(qū)的認(rèn)證信息,字節(jié)大小,最后一次粘附時(shí)間、分離時(shí)間、改變時(shí)間,創(chuàng)建該共享區(qū)域的進(jìn)程,最后一次對(duì)它操作的進(jìn)程,當(dāng)前有多少個(gè)進(jìn)程在使用它等信息。
            ????其定義如下:
            ????struct shmid_ds {
            ????????struct ipc_perm shm_perm;??
            ????????int shm_segsz;?????????????
            ????????__kernel_time_t shm_atime;?
            ????????__kernel_time_t shm_dtime;?
            ????????__kernel_time_t shm_ctime;?
            ????????__kernel_ipc_pid_t shm_cpid;
            ????????__kernel_ipc_pid_t shm_lpid;
            ????????unsigned short shm_nattch;??
            ????????unsigned short shm_unused;??
            ????????void *shm_unused2;??????????
            ????????void *shm_unused3;??????????
            ????};

            ?
            ??????? attaches描述被共享的物理內(nèi)存對(duì)象所映射的各進(jìn)程的虛擬內(nèi)存區(qū)域。每一個(gè)希望共享這塊內(nèi)存的進(jìn)程都必須通過(guò)系統(tǒng)調(diào)用將其關(guān)聯(lián)(attach)到它的虛擬內(nèi)存中。這一過(guò)程將為該進(jìn)程創(chuàng)建了一個(gè)新的描述這塊共享內(nèi)存的vm_area_struct數(shù)據(jù)結(jié)構(gòu)。創(chuàng)建時(shí)可以指定共享內(nèi)存在它的虛擬地址空間的位置,也可以讓Linux自己為它選擇一塊足夠的空閑區(qū)域。
            ?
            ????????這個(gè)新的vm_area_struct結(jié)構(gòu)是維系共享內(nèi)存和使用它的進(jìn)程之間的關(guān)系的,所以除了要關(guān)聯(lián)進(jìn)程信息外,還要指明這個(gè)共享內(nèi)存數(shù)據(jù)結(jié)構(gòu)shmid_kernel所在位置; 另外,便于管理這些經(jīng)常變化的vm_area_struct,所以采取了鏈表形式組織這些數(shù)據(jù)結(jié)構(gòu),鏈表由attaches指向,同時(shí) vm_area_struct數(shù)據(jù)結(jié)構(gòu)中專門(mén)提供了兩個(gè)指針:vm_next_shared和 vm_prev_shared,用于連接該共享區(qū)域在使用它的各進(jìn)程中所對(duì)應(yīng)的vm_area_struct數(shù)據(jù)結(jié)構(gòu)。?

            圖 System V IPC 機(jī)制 - 共享內(nèi)存?
            Linux?<wbr>進(jìn)程間通信?<wbr>-?<wbr>共享內(nèi)存shmget方式

            ?????????????Linux為共享內(nèi)存提供了四種操作。
            ????????1. 共享內(nèi)存對(duì)象的創(chuàng)建或獲得。與其它兩種IPC機(jī)制一樣,進(jìn)程在使用共享內(nèi)存區(qū)域以前,必須通過(guò)系統(tǒng)調(diào)用sys_ipc (call值為SHMGET)創(chuàng)建一個(gè)鍵值為key的共享內(nèi)存對(duì)象,或獲得已經(jīng)存在的鍵值為key的某共享內(nèi)存對(duì)象的引用標(biāo)識(shí)符。以后對(duì)共享內(nèi)存對(duì)象的訪問(wèn)都通過(guò)該引用標(biāo)識(shí)符進(jìn)行。對(duì)共享內(nèi)存對(duì)象的創(chuàng)建或獲得由函數(shù)sys_shmget完成,其定義如下:
            int sys_shmget (key_t key, int size, int shmflg)
            ?
            ??? 這里key是表示該共享內(nèi)存對(duì)象的鍵值,size是該共享內(nèi)存區(qū)域的大小(以字節(jié)為單位),shmflg是標(biāo)志(對(duì)該共享內(nèi)存對(duì)象的特殊要求)。
            ?
            ??? 它所做的工作如下:
            ??? 1) 如果key == IPC_PRIVATE,則總是會(huì)創(chuàng)建一個(gè)新的共享內(nèi)存對(duì)象。
            ?但是? (The name choice IPC_PRIVATE was perhaps unfortunate, IPC_NEW would more?clearly show its function)
            ??? * 算出size要占用的頁(yè)數(shù),檢查其合法性。
            ??? * 申請(qǐng)一塊內(nèi)存用于建立shmid_kernel數(shù)據(jù)結(jié)構(gòu),注意這里申請(qǐng)的內(nèi)存區(qū)域大小不包括真正的共享內(nèi)存區(qū),實(shí)際上,要等到第一個(gè)進(jìn)程試圖訪問(wèn)它的時(shí)候才真正創(chuàng)建共享內(nèi)存區(qū)。
            ??? * 根據(jù)該共享內(nèi)存區(qū)所占用的頁(yè)數(shù),為其申請(qǐng)一塊空間用于建立頁(yè)表(每頁(yè)4個(gè)字節(jié)),將頁(yè)表清0。
            ??? * 搜索向量表shm_segs,為新創(chuàng)建的共享內(nèi)存對(duì)象找一個(gè)空位置。
            ??? * 填寫(xiě)shmid_kernel數(shù)據(jù)結(jié)構(gòu),將其加入到向量表shm_segs中為其找到的空位置。
            ??? * 返回該共享內(nèi)存對(duì)象的引用標(biāo)識(shí)符。
            ?
            ??? 2) 在向量表shm_segs中查找鍵值為key的共享內(nèi)存對(duì)象,結(jié)果有三:
            ??? * 如果沒(méi)有找到,而且在操作標(biāo)志shmflg中沒(méi)有指明要?jiǎng)?chuàng)建新共享內(nèi)存,則錯(cuò)誤返回,否則創(chuàng)建一個(gè)新的共享內(nèi)存對(duì)象。
            ??? * 如果找到了,但該次操作要求必須創(chuàng)建一個(gè)鍵值為key的新對(duì)象,那么錯(cuò)誤返回。
            ??? * 否則,合法性、認(rèn)證檢查,如有錯(cuò),則錯(cuò)誤返回;否則,返回該內(nèi)存對(duì)象的引用標(biāo)識(shí)符。
            ?
            ??? 共享內(nèi)存對(duì)象的創(chuàng)建者可以控制對(duì)于這塊內(nèi)存的訪問(wèn)權(quán)限和它的key是公開(kāi)還是私有。如果有足夠的權(quán)限,它也可以把共享內(nèi)存鎖定在物理內(nèi)存中。
            ??? 參見(jiàn)include/linux/shm.h
            ?
            ??? 2. 關(guān)聯(lián)。在創(chuàng)建或獲得某個(gè)共享內(nèi)存區(qū)域的引用標(biāo)識(shí)符后,還必須將共享內(nèi)存區(qū)域映射(粘附)到進(jìn)程的虛擬地址空間,然后才能使用該共享內(nèi)存區(qū)域。系統(tǒng)調(diào)用 sys_ipc(call值為SHMAT)用于共享內(nèi)存區(qū)到進(jìn)程虛擬地址空間的映射,而真正完成粘附動(dòng)作的是函數(shù)sys_shmat,
            ?
            其定義如下:???

            ???????#include <sys/types.h>
            ?????? #include <sys/shm.h>

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


            ?
            ??? 其中:
            ???? shmid是shmget返回的共享內(nèi)存對(duì)象的引用標(biāo)識(shí)符;
            ??? shmaddr用來(lái)指定該共享內(nèi)存區(qū)域在進(jìn)程的虛擬地址空間對(duì)應(yīng)的虛擬地址;
            ??? shmflg是映射標(biāo)志;
            ????返回的是在進(jìn)程中的虛擬地址
            ?
            ??? 該函數(shù)所做的工作如下:
            ??? 1) 根據(jù)shmid找到共享內(nèi)存對(duì)象。
            ??? 2) 如果shmaddr為0,即用戶沒(méi)有指定該共享內(nèi)存區(qū)域在它的虛擬空間中的位置,則由系統(tǒng)在進(jìn)程的虛擬地址空間中為其找一塊區(qū)域(從1G開(kāi)始);否則,就用shmaddr作為映射的虛擬地址。
            ??(If? shmaddr? is NULL, the system chooses a suitable (unused) address a他 which to attach the segment)
            ??? 3) 檢查虛擬地址的合法性(不能超過(guò)進(jìn)程的最大虛擬空間大小—3G,不能太接近堆棧棧頂)。
            ??? 4) 認(rèn)證檢查。
            ??? 5) 申請(qǐng)一塊內(nèi)存用于建立數(shù)據(jù)結(jié)構(gòu)vm_area_struct,填寫(xiě)該結(jié)構(gòu)。
            ??? 6) 檢查該內(nèi)存區(qū)域,將其加入到進(jìn)程的mm結(jié)構(gòu)和該共享內(nèi)存對(duì)象的vm_area_struct隊(duì)列中。
            ?
            ??? 共享內(nèi)存的粘附只是創(chuàng)建一個(gè)vm_area_struct數(shù)據(jù)結(jié)構(gòu),并將其加入到相應(yīng)的隊(duì)列中,此時(shí)并沒(méi)有創(chuàng)建真正的共享內(nèi)存頁(yè)。
            ?
            ??? 當(dāng)進(jìn)程第一次訪問(wèn)共享虛擬內(nèi)存的某頁(yè)時(shí),因?yàn)樗械墓蚕韮?nèi)存頁(yè)還都沒(méi)有分配,所以會(huì)發(fā)生一個(gè)page fault異常。當(dāng)Linux處理這個(gè)page fault的時(shí)候,它找到發(fā)生異常的虛擬地址所在的vm_area_struct數(shù)據(jù)結(jié)構(gòu)。在該數(shù)據(jù)結(jié)構(gòu)中包含有這類共享虛擬內(nèi)存的一組處理程序,其中的 nopage操作用來(lái)處理虛擬頁(yè)對(duì)應(yīng)的物理頁(yè)不存在的情況。對(duì)共享內(nèi)存,該操作是shm_nopage(定義在ipc/shm.c中)。該操作在描述這個(gè)共享內(nèi)存的shmid_kernel數(shù)據(jù)結(jié)構(gòu)的頁(yè)表shm_pages中查找發(fā)生page fault異常的虛擬地址所對(duì)應(yīng)的頁(yè)表?xiàng)l目,看共享頁(yè)是否存在(頁(yè)表?xiàng)l目為0,表示共享頁(yè)是第一次使用)。如果不存在,它就分配一個(gè)物理頁(yè),并為它創(chuàng)建一個(gè)頁(yè)表?xiàng)l目。這個(gè)條目不但進(jìn)入當(dāng)前進(jìn)程的頁(yè)表,同時(shí)也存到shmid_kernel數(shù)據(jù)結(jié)構(gòu)的頁(yè)表shm_pages中。
            ?
            ??? 當(dāng)下一個(gè)進(jìn)程試圖訪問(wèn)這塊內(nèi)存并得到一個(gè)page fault的時(shí)候,經(jīng)過(guò)同樣的路徑,也會(huì)走到函數(shù)shm_nopage。此時(shí),該函數(shù)查看shmid_kernel數(shù)據(jù)結(jié)構(gòu)的頁(yè)表shm_pages時(shí),發(fā)現(xiàn)共享頁(yè)已經(jīng)存在,它只需把這里的頁(yè)表項(xiàng)填到進(jìn)程頁(yè)表的相應(yīng)位置即可,而不需要重新創(chuàng)建物理頁(yè)。所以,是第一個(gè)訪問(wèn)共享內(nèi)存頁(yè)的進(jìn)程使得這一頁(yè)被創(chuàng)建,而隨后訪問(wèn)它的其它進(jìn)程僅把此頁(yè)加到它們的虛擬地址空間。
            ?
            ??? 3. 分離。當(dāng)進(jìn)程不再需要共享虛擬內(nèi)存的時(shí)候,它們與之分離(detach)。只要仍舊有其它進(jìn)程在使用這塊內(nèi)存,這種分離就只會(huì)影響當(dāng)前的進(jìn)程,而不會(huì)影響其它進(jìn)程。當(dāng)前進(jìn)程的vm_area_struct數(shù)據(jù)結(jié)構(gòu)被從shmid_ds中刪除,并被釋放。當(dāng)前進(jìn)程的頁(yè)表也被更新,共享內(nèi)存對(duì)應(yīng)的虛擬內(nèi)存頁(yè)被標(biāo)記為無(wú)效。當(dāng)共享這塊內(nèi)存的最后一個(gè)進(jìn)程與之分離時(shí),共享內(nèi)存頁(yè)被釋放,同時(shí),這塊共享內(nèi)存的shmid_kernel數(shù)據(jù)結(jié)構(gòu)也被釋放。
            ?
            ? 系統(tǒng)調(diào)用sys_ipc (call值為SHMDT) 用于共享內(nèi)存區(qū)與進(jìn)程虛擬地址空間的分離,而真正完成分離動(dòng)作的是函數(shù)????

            ??? sys_shmdt,其定義如下:
            ??? int sys_shmdt (char *shmaddr)
            ?
            ??? 其中shmaddr是進(jìn)程要分離的共享頁(yè)的開(kāi)始虛擬地址。
            ?
            ??? 該函數(shù)搜索進(jìn)程的內(nèi)存結(jié)構(gòu)中的所有vm_area_struct數(shù)據(jù)結(jié)構(gòu),找到地址shmaddr對(duì)應(yīng)的一個(gè),調(diào)用函數(shù)do_munmap將其釋放。
            ?
            ??? 在函數(shù)do_munmap中,將要釋放的vm_area_struct數(shù)據(jù)結(jié)構(gòu)從進(jìn)程的虛擬內(nèi)存中摘下,清除它在進(jìn)程頁(yè)表中對(duì)應(yīng)的頁(yè)表項(xiàng)(可能占多個(gè)頁(yè)表項(xiàng)).?
            ??
            ??? 如果共享的虛擬內(nèi)存沒(méi)有被鎖定在物理內(nèi)存中,分離會(huì)更加復(fù)雜。因?yàn)樵谶@種情況下,共享內(nèi)存的頁(yè)可能在系統(tǒng)大量使用內(nèi)存的時(shí)候被交換到系統(tǒng)的交換磁盤(pán)。為了避免這種情況,可以通過(guò)下面的控制操作,將某共享內(nèi)存頁(yè)鎖定在物理內(nèi)存不允許向外交換。共享內(nèi)存的換出和換入,已在第3章中討論。
            ?
            ??? 4. 控制。Linux在共享內(nèi)存上實(shí)現(xiàn)的第四種操作是共享內(nèi)存的控制(call值為SHMCTL的sys_ipc調(diào)用),它由函數(shù)sys_shmctl實(shí)現(xiàn)??刂撇僮靼ǐ@得共享內(nèi)存對(duì)象的狀態(tài),設(shè)置共享內(nèi)存對(duì)象的參數(shù)(如uid、gid、mode、ctime等),將共享內(nèi)存對(duì)象在內(nèi)存中鎖定和釋放(在對(duì)象的mode上增加或去除SHM_LOCKED標(biāo)志),釋放共享內(nèi)存對(duì)象資源等。
            ?
            ??? 共享內(nèi)存提供了一種快速靈活的機(jī)制,它允許進(jìn)程之間直接共享大量的數(shù)據(jù),而無(wú)須使用拷貝或系統(tǒng)調(diào)用。共享內(nèi)存的主要局限性是它不能提供同步,如果兩個(gè)進(jìn)程企圖修改相同的共享內(nèi)存區(qū)域,由于內(nèi)核不能串行化這些動(dòng)作,因此寫(xiě)的數(shù)據(jù)可能任意地互相混合。所以使用共享內(nèi)存的進(jìn)程必須設(shè)計(jì)它們自己的同步協(xié)議,如用信號(hào)燈等。

            以下是使用共享內(nèi)存機(jī)制進(jìn)行進(jìn)程間通信的基本操作:

            需要包含的頭文件:

            #include <sys/types.h>

            #include <sys/ipc.h>

            #include <sys/shm.h>

            1.創(chuàng)建共享內(nèi)存:

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

            參數(shù)說(shuō)明:

            key:用來(lái)表示新建或者已經(jīng)存在的共享內(nèi)存去的關(guān)鍵字。

            size:創(chuàng)建共享內(nèi)存的大小。

            shmflg:可以指定的特殊標(biāo)志。IPC_CREATE,IPC_EXCL以及低九位的權(quán)限。

            eg:

            int shmid;

            shmid=shmget(IPC_PRIVATE,4096,IPC_CREATE|IPC_EXCL|0660);

            if(shmid==-1)

            perror("shmget()");

            ?

            2.連接共享內(nèi)存

            char *shmat(int shmid,char *shmaddr,int shmflg);

            參數(shù)說(shuō)明

            shmid:共享內(nèi)存的關(guān)鍵字

            shmaddr:指定共享內(nèi)存出現(xiàn)在進(jìn)程內(nèi)存地址的什么位置,通常我們讓內(nèi)核自己決定一個(gè)合適的地址位置,用的時(shí)候設(shè)為0。

            shmflg:制定特殊的標(biāo)志位。

            eg:

            int shmid;

            char *shmp;

            shmp=shmat(shmid,0,0);

            if(shmp==(char *)(-1))

            perror("shmat()\n");

            3.使用共享內(nèi)存

            在使用共享內(nèi)存是需要注意的是,為防止內(nèi)存訪問(wèn)沖突,我們一般與信號(hào)量結(jié)合使用。

            4.分離共享內(nèi)存:當(dāng)程序不再需要共享內(nèi)后,我們需要將共享內(nèi)存分離以便對(duì)其進(jìn)行釋放,分離共享內(nèi)存的函數(shù)原形如下:

            int shmdt(char *shmaddr);

            ?

            5. 釋放共享內(nèi)存

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

            *****************示例**********************

            int??*__accept_socketfd;

            ?int shmid = shmget(SHAREMEMID,sizeof(int),IPC_CREAT|0666);?
            ?
            ?if (( __accept_socketfd = (int *)shmat(shmid,NULL,0 )) == (int *)-1 )
            ?{
            ??printf("Error:shmat\n");
            ??return;
            ?}
            ??? *__accept_socketfd = 0;

            Feedback

            # re: Linux 進(jìn)程間通信 - 共享內(nèi)存shmget方式[未登錄](méi)  回復(fù)  更多評(píng)論   

            2012-09-13 15:52 by 初學(xué)者
            學(xué)習(xí)了,真的挺好,謝謝~
            色综合久久精品中文字幕首页| 久久99精品久久久久久9蜜桃| 一本久久a久久精品综合香蕉| 性做久久久久久久| 91精品国产乱码久久久久久| 亚洲欧美日韩精品久久亚洲区| 久久综合狠狠综合久久综合88| 亚洲一本综合久久| 99久久精品国产一区二区| 亚洲成人精品久久| 久久99久久99精品免视看动漫| 大美女久久久久久j久久| 狠狠综合久久AV一区二区三区| 久久天天躁狠狠躁夜夜2020老熟妇| 亚洲精品乱码久久久久久久久久久久| 久久电影网2021| 久久久久亚洲AV无码麻豆| 久久国产精品无码网站| 国产精品久久久久影院色| 漂亮人妻被中出中文字幕久久| 成人a毛片久久免费播放| 久久精品亚洲日本波多野结衣| 精品国产乱码久久久久久人妻| 久久久久久极精品久久久| 久久―日本道色综合久久| 久久久精品2019免费观看| 久久久久亚洲av综合波多野结衣| 国产精品成人99久久久久 | 99久久99久久精品国产片果冻| 国产亚洲成人久久| 99久久99久久精品国产片果冻| 久久青青草原综合伊人| AV无码久久久久不卡蜜桃| 狠狠色丁香久久婷婷综合五月 | 亚洲伊人久久综合影院| 久久国产一片免费观看| 国产一区二区精品久久岳| 深夜久久AAAAA级毛片免费看| 久久精品国产亚洲AV不卡| 久久亚洲高清综合| 日韩欧美亚洲综合久久 |