溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

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

發(fā)布時間:2021-09-27 14:04:15 來源:億速云 閱讀:185 作者:iii 欄目:系統(tǒng)運維

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

兩個甚至多個進程使用共享內(nèi)存(shm)通信,總遇到同步問題。這里的“同步問題”不是說進程讀寫同步問題,這個用信號量就好了。這里的同步問題說的是同步退出問題,到底誰先退出,怎么知道對方退出了。舉個例子:進程負責(zé)讀寫數(shù)據(jù)庫A,進程B負責(zé)處理數(shù)據(jù)。那么進程A得比進程B晚退出才行,因為要保存進程B處理完的數(shù)據(jù)??墒牵敛恢溃率裁磿r候退出啊。A、B是無關(guān)聯(lián)的進程,也不知道對方的pid。它們唯一的關(guān)聯(lián)就是讀寫同一塊共享內(nèi)存。正常情況下,進程B在共享內(nèi)存中寫個標識:進程A你可以退出了,也是可以的。不過進程B可能是異常退出,連標識都來不及寫。其次,共享內(nèi)存用來做數(shù)據(jù)通信的,加這么個標識感覺不太好,有濫用的感覺。

  采用socket通信沒有這個問題,因為進程B退出怎么也會導(dǎo)致socket斷開,哪怕是超時。但shm卻沒有協(xié)議來檢測這些行為,如果自己也做一個未免太麻煩。那就從共享內(nèi)存下手吧。

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

  在System V的共享內(nèi)存中,創(chuàng)建一個共享內(nèi)存會初始化一個結(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)存的進程數(shù)。

  不過,現(xiàn)在有了新的POSIX標準,當然要用新標準了。shm_open創(chuàng)建的共享內(nèi)存也具有“一個進程刪除本身打開的共享內(nèi)存并不影響另一個進程的共享內(nèi)存”的特點??墒怯胹hm_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)建一個普通的文件啊,只是創(chuàng)建的位置在/dev/shm下(也就是RAM上)。再來看看刪除共享內(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;
}

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

  不過,在linux下怎么會有解決不了的問題呢?解決不了只能說明自己太菜。既然是文件,那就從文件下手。那文件有什么是原子操作,又可以計數(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)
最近訪問:2015-01-25 21:27:00.961053098 +0800
最近更改:2015-01-25 21:27:00.961053098 +0800
最近改動:2015-01-25 21:27:00.961053098 +0800
創(chuàng)建時間:-
xzc@xzc-HP-ProBook-4446s:/dev/shm$

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

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

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

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

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI