本篇內容主要講解“如何解決linux使用共享內存通信的進程同步退出問題”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“如何解決linux使用共享內存通信的進程同步退出問題”吧!
為企業(yè)提供成都網站設計、網站制作、網站優(yōu)化、全網營銷推廣、競價托管、品牌運營等營銷獲客服務。成都創(chuàng)新互聯(lián)公司擁有網絡營銷運營團隊,以豐富的互聯(lián)網營銷經驗助力企業(yè)精準獲客,真正落地解決中小企業(yè)營銷獲客難題,做到“讓獲客更簡單”。自創(chuàng)立至今,成功用技術實力解決了企業(yè)“網站建設、網絡品牌塑造、網絡營銷”三大難題,同時降低了營銷成本,提高了有效客戶轉化率,獲得了眾多企業(yè)客戶的高度認可!
兩個甚至多個進程使用共享內存(shm)通信,總遇到同步問題。這里的“同步問題”不是說進程讀寫同步問題,這個用信號量就好了。這里的同步問題說的是同步退出問題,到底誰先退出,怎么知道對方退出了。舉個例子:進程負責讀寫數據庫A,進程B負責處理數據。那么進程A得比進程B晚退出才行,因為要保存進程B處理完的數據??墒牵敛恢溃率裁磿r候退出啊。A、B是無關聯(lián)的進程,也不知道對方的pid。它們唯一的關聯(lián)就是讀寫同一塊共享內存。正常情況下,進程B在共享內存中寫個標識:進程A你可以退出了,也是可以的。不過進程B可能是異常退出,連標識都來不及寫。其次,共享內存用來做數據通信的,加這么個標識感覺不太好,有濫用的感覺。
采用socket通信沒有這個問題,因為進程B退出怎么也會導致socket斷開,哪怕是超時。但shm卻沒有協(xié)議來檢測這些行為,如果自己也做一個未免太麻煩。那就從共享內存下手吧。
共享內存是由內核來管理的,一個進程刪除本身打開的共享內存并不影響另一個進程的共享內存,哪怕都是同一塊共享內存。這是因為共享內存在內核中一個引用計數,一個進程使用該共享內存就會導致引用計數加1。如果其中一個進程調用了刪除函數,只有這個計數為0才會真正刪除共享內存。那么,需要最后才退出的進程檢測這個計數就可以了。
在System V的共享內存中,創(chuàng)建一個共享內存會初始化一個結構:
代碼如下:
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創(chuàng)建的共享內存也具有“一個進程刪除本身打開的共享內存并不影響另一個進程的共享內存”的特點??墒怯胹hm_open創(chuàng)建的共享內存不再有上面的結構,那么,內核是怎么管理shm_open創(chuàng)建共享內存??看下面的源碼:
代碼如下:
/* shm_open - open a shared memory file */
/* Copyright 2002, Red Hat Inc. */
#include
#include
#include
#include
#include
#include
int
shm_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;
}
我嚓,這就是創(chuàng)建一個普通的文件啊,只是創(chuàng)建的位置在/dev/shm下(也就是RAM上)。再來看看刪除共享內存的函數shm_unlink:
代碼如下:
/* shm_unlink - remove a shared memory file */
/* Copyright 2002, Red Hat Inc. */
#include
#include
#include
#include
#include
int
shm_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下怎么會有解決不了的問題呢?解決不了只能說明自己太菜。既然是文件,那就從文件下手。那文件有什么是原子操作,又可以計數的呢。答案:硬鏈接。比如:
代碼如下:
xzc@xzc-HP-ProBook-4446s:/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
創(chuàng)建時間:-
xzc@xzc-HP-ProBook-4446s:/dev/shm$
這個硬鏈接可以通過fstat函數獲取。可是要這樣實現的話,意味著需要先創(chuàng)建一塊共享內存,每個進程引用的時候需要調用link函數來創(chuàng)建一個硬鏈接。問題解決了,可是這樣會在/dev/shm下多個N多個文件。這可是RAM啊,雖然現在的服務器都比較牛,但這樣做也不太好吧。好吧,還有一個flock文件鎖。flock使用LOCK_SH參數多個進程對同一個文件加鎖。這樣,進程B初始化共享內存時加鎖(可以有多個這樣的進程),在退出(包括異常退出)時解鎖。進程A在退出時檢測這個鎖。當發(fā)現無鎖時說明可以安全退出了。
同步退出的問題基本解決了。來不及寫代碼去驗證,下次吧。
PS:內核unlink時應該也是有計數才知道當前有沒有進程打開文件,在什么時候應該刪除文件。這個還得去查資料,看用不用得上。另外lsof這個工具是可以檢測到所有打開該共享內存的進程及相應的狀態(tài)。這個應該也是有對應的api的,只是現在還沒搞懂。
到此,相信大家對“如何解決linux使用共享內存通信的進程同步退出問題”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!