linux使用共用記憶體通訊的進程同步退出問題

來源:互聯網
上載者:User

標籤:

  兩個甚至多個進程使用共用記憶體(shm)通訊,總遇到同步問題。這裡的“同步問題”不是說進程讀寫同步問題,這個用訊號量就好了。這裡的同步問題說的是同步退出問題,到底誰先退出,怎麼知道對方退出了。舉個例子:進程負責讀寫資料庫A,進程B負責處理資料。那麼進程A得比進程B晚退出才行,因為要儲存進程B處理完的資料。可是A不知道B什麼時候退出啊。A、B是無關聯的進程,也不知道對方的pid。它們唯一的關聯就是讀寫同一塊共用記憶體。正常情況下,進程B在共用記憶體中寫個標識:進程A你可以退出了,也是可以的。不過進程B可能是異常退出,連標識都來不及寫。其次,共用記憶體用來做資料通訊的,加這麼個標識感覺不太好,有濫用的感覺。

  採用socket通訊沒有這個問題,因為進程B退出怎麼也會導致socket斷開,哪怕是逾時。但shm卻沒有協議來檢測這些行為,如果自己也做一個未免太麻煩。那就從共用記憶體下手吧。

  共用記憶體是由核心來管理的,一個進程刪除本身開啟的共用記憶體並不影響另一個進程的共用記憶體,哪怕都是同一塊共用記憶體。這是因為共用記憶體在核心中一個引用計數,一個進程使用該共用記憶體就會導致引用計數加1。如果其中一個進程調用了刪除函數,只有這個計數為0才會真正刪除共用記憶體。那麼,需要最後才退出的進程檢測這個計數就可以了。

  在System V的共用記憶體中,建立一個共用記憶體會初始化一個結構:

           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函數可以讀取該結構體,其中的shm_nattch就是使用該共用記憶體的進程數。

  不過,現在有了新的POSIX標準,當然要用新標準了。shm_open建立的共用記憶體也具有“一個進程刪除本身開啟的共用記憶體並不影響另一個進程的共用記憶體”的特點。可是用shm_open建立的共用記憶體不再有上面的結構,那麼,核心是怎麼管理shm_open建立共用記憶體??看下面的源碼:

/* shm_open - open a shared memory file *//* Copyright 2002, Red Hat Inc. */#include <sys/types.h>#include <sys/mman.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <limits.h>intshm_open (const char *name, int oflag, mode_t mode){  int fd;  char shm_name[PATH_MAX+20] = "/dev/shm/";  /* skip opening slash */  if (*name == ‘/‘)    ++name;  /* 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);  fd = open (shm_name, oflag, mode);  if (fd != -1)    {      /* once open we must add FD_CLOEXEC flag to file descriptor */      int flags = fcntl (fd, F_GETFD, 0);      if (flags >= 0)        {          flags |= FD_CLOEXEC;          flags = fcntl (fd, F_SETFD, flags);        }      /* on failure, just close file and give up */      if (flags == -1)        {          close (fd);          fd = -1;        }    }  return fd;}

我嚓,這就是建立一個普通的檔案啊,只是建立的位置在/dev/shm下(也就是RAM上)。再來看看刪除共用記憶體的函數shm_unlink:

/* shm_unlink - remove a shared memory file *//* Copyright 2002, Red Hat Inc. */#include <sys/types.h>#include <sys/mman.h>#include <unistd.h>#include <string.h>#include <limits.h>intshm_unlink (const char *name){  int rc;  char shm_name[PATH_MAX+20] = "/dev/shm/";  /* skip opening slash */  if (*name == ‘/‘)    ++name;  /* 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);  rc = unlink (shm_name);  return rc;}

這也只是一個普通的unlink函數。也就是說,POSIX標準的共用記憶體就是一個檔案。所謂的“一個進程刪除本身開啟的共用記憶體並不影響另一個進程的共用記憶體”就相當於你用fstream對象開啟了一個檔案,然後去檔案夾把檔案刪除了(也就是對檔案進行了unlink操作),可是fstream對象還可以正常讀寫檔案,並沒有什麼引用計數。這下好了,進程退出時又沒法同步了。

  不過,在linux下怎麼會有解決不了的問題呢?解決不了只能說明自己太菜。既然是檔案,那就從檔案下手。那檔案有什麼是原子操作,又可以計數的呢。答案:永久連結。比如:

[email protected]:/dev/shm$ stat abc  檔案:"abc"  大小:4             塊:8          IO 塊:4096   普通檔案裝置:15h/21d    Inode:5743159     永久連結:1許可權:(0664/-rw-rw-r--)  Uid:( 1000/     xzc)   Gid:( 1000/     xzc)最近訪問:2015-01-25 21:27:00.961053098 +0800最近更改:2015-01-25 21:27:00.961053098 +0800最近改動:2015-01-25 21:27:00.961053098 +0800建立時間:-[email protected]-HP-ProBook-4446s:/dev/shm$ 

這個永久連結可以通過fstat函數擷取。可是要這樣實現的話,意味著需要先建立一塊共用記憶體,每個進程引用的時候需要調用link函數來建立一個永久連結。問題解決了,可是這樣會在/dev/shm下多個N多個檔案。這可是RAM啊,雖然現在的伺服器都比較牛,但這樣做也不太好吧。好吧,還有一個flock檔案鎖。flock使用LOCK_SH參數多個進程對同一個檔案加鎖。這樣,進程B初始化共用記憶體時加鎖(可以有多個這樣的進程),在退出(包括異常退出)時解鎖。進程A在退出時檢測這個鎖。當發現無鎖時說明可以安全退出了。

  同步退出的問題基本解決了。來不及寫代碼去驗證,下次吧。

PS:核心unlink時應該也是有計數才知道當前有沒有進程開啟檔案,在什麼時候應該刪除檔案。這個還得去查資料,看用不用得上。另外lsof這個工具是可以檢測到所有開啟該共用記憶體的進程及相應的狀態。這個應該也是有對應的api的,只是現在還沒搞懂。

linux使用共用記憶體通訊的進程同步退出問題

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.