两个甚至多个进程使用共享内存(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 */</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;
}
我嚓,这就是创建一个普通的文件啊,只是创建的位置在/dev/shm下(也就是RAM上)。再来看看删除共享内存的函数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函数。也就是说,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
创建时间:-
xzc@xzc-HP-ProBook-4446s:/dev/shm$
这个硬链接可以通过fstat函数获取。可是要这样实现的话,意味着需要先创建一块共享内存,每个进程引用的时候需要调用link函数来创建一个硬链接。问题解决了,可是这样会在/dev/shm下多个N多个文件。这可是RAM啊,虽然现在的服务器都比较牛,但这样做也不太好吧。好吧,还有一个flock文件锁。flock使用LOCK_SH参数多个进程对同一个文件加锁。这样,进程B初始化共享内存时加锁(可以有多个这样的进程),在退出(包括异常退出)时解锁。进程A在退出时检测这个锁。当发现无锁时说明可以安全退出了。
同步退出的问题基本解决了。来不及写代码去验证,下次吧。
PS:内核unlink时应该也是有计数才知道当前有没有进程打开文件,在什么时候应该删除文件。这个还得去查资料,看用不用得上。另外lsof这个工具是可以检测到所有打开该共享内存的进程及相应的状态。这个应该也是有对应的api的,只是现在还没搞懂。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]