如何解決linux使用共享內(nèi)存通信的進(jìn)程同步退出問(wèn)題

本篇內(nèi)容主要講解“如何解決linux使用共享內(nèi)存通信的進(jìn)程同步退出問(wèn)題”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“如何解決linux使用共享內(nèi)存通信的進(jìn)程同步退出問(wèn)題”吧!

為企業(yè)提供成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、網(wǎng)站優(yōu)化、全網(wǎng)營(yíng)銷(xiāo)推廣、競(jìng)價(jià)托管、品牌運(yùn)營(yíng)等營(yíng)銷(xiāo)獲客服務(wù)。成都創(chuàng)新互聯(lián)公司擁有網(wǎng)絡(luò)營(yíng)銷(xiāo)運(yùn)營(yíng)團(tuán)隊(duì),以豐富的互聯(lián)網(wǎng)營(yíng)銷(xiāo)經(jīng)驗(yàn)助力企業(yè)精準(zhǔn)獲客,真正落地解決中小企業(yè)營(yíng)銷(xiāo)獲客難題,做到“讓獲客更簡(jiǎn)單”。自創(chuàng)立至今,成功用技術(shù)實(shí)力解決了企業(yè)“網(wǎng)站建設(shè)、網(wǎng)絡(luò)品牌塑造、網(wǎng)絡(luò)營(yíng)銷(xiāo)”三大難題,同時(shí)降低了營(yíng)銷(xiāo)成本,提高了有效客戶(hù)轉(zhuǎn)化率,獲得了眾多企業(yè)客戶(hù)的高度認(rèn)可!

兩個(gè)甚至多個(gè)進(jìn)程使用共享內(nèi)存(shm)通信,總遇到同步問(wèn)題。這里的“同步問(wèn)題”不是說(shuō)進(jìn)程讀寫(xiě)同步問(wèn)題,這個(gè)用信號(hào)量就好了。這里的同步問(wèn)題說(shuō)的是同步退出問(wèn)題,到底誰(shuí)先退出,怎么知道對(duì)方退出了。舉個(gè)例子:進(jìn)程負(fù)責(zé)讀寫(xiě)數(shù)據(jù)庫(kù)A,進(jìn)程B負(fù)責(zé)處理數(shù)據(jù)。那么進(jìn)程A得比進(jìn)程B晚退出才行,因?yàn)橐4孢M(jìn)程B處理完的數(shù)據(jù)。可是A不知道B什么時(shí)候退出啊。A、B是無(wú)關(guān)聯(lián)的進(jìn)程,也不知道對(duì)方的pid。它們唯一的關(guān)聯(lián)就是讀寫(xiě)同一塊共享內(nèi)存。正常情況下,進(jìn)程B在共享內(nèi)存中寫(xiě)個(gè)標(biāo)識(shí):進(jìn)程A你可以退出了,也是可以的。不過(guò)進(jìn)程B可能是異常退出,連標(biāo)識(shí)都來(lái)不及寫(xiě)。其次,共享內(nèi)存用來(lái)做數(shù)據(jù)通信的,加這么個(gè)標(biāo)識(shí)感覺(jué)不太好,有濫用的感覺(jué)。

采用socket通信沒(méi)有這個(gè)問(wèn)題,因?yàn)檫M(jìn)程B退出怎么也會(huì)導(dǎo)致socket斷開(kāi),哪怕是超時(shí)。但shm卻沒(méi)有協(xié)議來(lái)檢測(cè)這些行為,如果自己也做一個(gè)未免太麻煩。那就從共享內(nèi)存下手吧。

共享內(nèi)存是由內(nèi)核來(lái)管理的,一個(gè)進(jìn)程刪除本身打開(kāi)的共享內(nèi)存并不影響另一個(gè)進(jìn)程的共享內(nèi)存,哪怕都是同一塊共享內(nèi)存。這是因?yàn)楣蚕韮?nèi)存在內(nèi)核中一個(gè)引用計(jì)數(shù),一個(gè)進(jìn)程使用該共享內(nèi)存就會(huì)導(dǎo)致引用計(jì)數(shù)加1。如果其中一個(gè)進(jìn)程調(diào)用了刪除函數(shù),只有這個(gè)計(jì)數(shù)為0才會(huì)真正刪除共享內(nèi)存。那么,需要最后才退出的進(jìn)程檢測(cè)這個(gè)計(jì)數(shù)就可以了。

在System V的共享內(nèi)存中,創(chuàng)建一個(gè)共享內(nèi)存會(huì)初始化一個(gè)結(jié)構(gòu):

代碼如下:


struct shmid_ds {
              struct ipc_perm shm_perm;    /* Ownership and permissions */
              size_t          shm_segsz;   /* Size of segment (bytes) */
              time_t          shm_atime;   /* Last attach time */
              time_t          shm_dtime;   /* Last detach time */
              time_t          shm_ctime;   /* Last change time */
              pid_t           shm_cpid;    /* PID of creator */
              pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
              shmatt_t        shm_nattch;  /* No. of current attaches */
              ...
          };

使用shmctl函數(shù)可以讀取該結(jié)構(gòu)體,其中的shm_nattch就是使用該共享內(nèi)存的進(jìn)程數(shù)。

不過(guò),現(xiàn)在有了新的POSIX標(biāo)準(zhǔn),當(dāng)然要用新標(biāo)準(zhǔn)了。shm_open創(chuàng)建的共享內(nèi)存也具有“一個(gè)進(jìn)程刪除本身打開(kāi)的共享內(nèi)存并不影響另一個(gè)進(jìn)程的共享內(nèi)存”的特點(diǎn)。可是用shm_open創(chuàng)建的共享內(nèi)存不再有上面的結(jié)構(gòu),那么,內(nèi)核是怎么管理shm_open創(chuàng)建共享內(nèi)存??看下面的源碼:

代碼如下:


/* shm_open - open a shared memory file */</p> <p>/* Copyright 2002, Red Hat Inc. */</p> <p>#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h></p> <p>int
shm_open (const char *name, int oflag, mode_t mode)
{
 int fd;
 char shm_name[PATH_MAX+20] = "/dev/shm/";</p> <p>  /* skip opening slash */
 if (*name == '/')
   ++name;</p> <p>  /* create special shared memory file name and leave enough space to
    cause a path/name error if name is too long */
 strlcpy (shm_name + 9, name, PATH_MAX + 10);</p> <p>  fd = open (shm_name, oflag, mode);</p> <p>  if (fd != -1)
   {
     /* once open we must add FD_CLOEXEC flag to file descriptor */
     int flags = fcntl (fd, F_GETFD, 0);</p> <p>      if (flags >= 0)
       {
         flags |= FD_CLOEXEC;
         flags = fcntl (fd, F_SETFD, flags);
       }</p> <p>      /* on failure, just close file and give up */
     if (flags == -1)
       {
         close (fd);
         fd = -1;
       }
   }</p> <p>  return fd;
}

我嚓,這就是創(chuàng)建一個(gè)普通的文件啊,只是創(chuàng)建的位置在/dev/shm下(也就是RAM上)。再來(lái)看看刪除共享內(nèi)存的函數(shù)shm_unlink:

代碼如下:


/* shm_unlink - remove a shared memory file */</p> <p>/* Copyright 2002, Red Hat Inc. */</p> <p>#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <limits.h></p> <p>int
shm_unlink (const char *name)
{
 int rc;
 char shm_name[PATH_MAX+20] = "/dev/shm/";</p> <p>  /* skip opening slash */
 if (*name == '/')
   ++name;</p> <p>  /* create special shared memory file name and leave enough space to
    cause a path/name error if name is too long */
 strlcpy (shm_name + 9, name, PATH_MAX + 10);</p> <p>  rc = unlink (shm_name);</p> <p>  return rc;
}

這也只是一個(gè)普通的unlink函數(shù)。也就是說(shuō),POSIX標(biāo)準(zhǔn)的共享內(nèi)存就是一個(gè)文件。所謂的“一個(gè)進(jìn)程刪除本身打開(kāi)的共享內(nèi)存并不影響另一個(gè)進(jìn)程的共享內(nèi)存”就相當(dāng)于你用fstream對(duì)象打開(kāi)了一個(gè)文件,然后去文件夾把文件刪除了(也就是對(duì)文件進(jìn)行了unlink操作),可是fstream對(duì)象還可以正常讀寫(xiě)文件,并沒(méi)有什么引用計(jì)數(shù)。這下好了,進(jìn)程退出時(shí)又沒(méi)法同步了。

不過(guò),在linux下怎么會(huì)有解決不了的問(wèn)題呢?解決不了只能說(shuō)明自己太菜。既然是文件,那就從文件下手。那文件有什么是原子操作,又可以計(jì)數(shù)的呢。答案:硬鏈接。比如:

代碼如下:


xzc@xzc-HP-ProBook-4446s:/dev/shm$ stat abc
 文件:"abc"
 大小:4             塊:8          IO 塊:4096   普通文件
設(shè)備:15h/21d    Inode:5743159     硬鏈接:1
權(quán)限:(0664/-rw-rw-r--)  Uid:( 1000/     xzc)   Gid:( 1000/     xzc)
最近訪問(wèn):2015-01-25 21:27:00.961053098 +0800
最近更改:2015-01-25 21:27:00.961053098 +0800
最近改動(dòng):2015-01-25 21:27:00.961053098 +0800
創(chuàng)建時(shí)間:-
xzc@xzc-HP-ProBook-4446s:/dev/shm$

這個(gè)硬鏈接可以通過(guò)fstat函數(shù)獲取??墒且@樣實(shí)現(xiàn)的話(huà),意味著需要先創(chuàng)建一塊共享內(nèi)存,每個(gè)進(jìn)程引用的時(shí)候需要調(diào)用link函數(shù)來(lái)創(chuàng)建一個(gè)硬鏈接。問(wèn)題解決了,可是這樣會(huì)在/dev/shm下多個(gè)N多個(gè)文件。這可是RAM啊,雖然現(xiàn)在的服務(wù)器都比較牛,但這樣做也不太好吧。好吧,還有一個(gè)flock文件鎖。flock使用LOCK_SH參數(shù)多個(gè)進(jìn)程對(duì)同一個(gè)文件加鎖。這樣,進(jìn)程B初始化共享內(nèi)存時(shí)加鎖(可以有多個(gè)這樣的進(jìn)程),在退出(包括異常退出)時(shí)解鎖。進(jìn)程A在退出時(shí)檢測(cè)這個(gè)鎖。當(dāng)發(fā)現(xiàn)無(wú)鎖時(shí)說(shuō)明可以安全退出了。

同步退出的問(wèn)題基本解決了。來(lái)不及寫(xiě)代碼去驗(yàn)證,下次吧。

PS:內(nèi)核unlink時(shí)應(yīng)該也是有計(jì)數(shù)才知道當(dāng)前有沒(méi)有進(jìn)程打開(kāi)文件,在什么時(shí)候應(yīng)該刪除文件。這個(gè)還得去查資料,看用不用得上。另外lsof這個(gè)工具是可以檢測(cè)到所有打開(kāi)該共享內(nèi)存的進(jìn)程及相應(yīng)的狀態(tài)。這個(gè)應(yīng)該也是有對(duì)應(yīng)的api的,只是現(xiàn)在還沒(méi)搞懂。

到此,相信大家對(duì)“如何解決linux使用共享內(nèi)存通信的進(jìn)程同步退出問(wèn)題”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!

網(wǎng)頁(yè)名稱(chēng):如何解決linux使用共享內(nèi)存通信的進(jìn)程同步退出問(wèn)題
新聞來(lái)源:http://muchs.cn/article48/jpiphp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供、網(wǎng)站內(nèi)鏈、網(wǎng)站設(shè)計(jì)、品牌網(wǎng)站制作、云服務(wù)器、網(wǎng)站導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司