linux使用共享内存通信的进程同步退出问题
两个甚至多个进程使用共享内存(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> int
shm_open (const char *name, int oflag, mode_t mode)
{
int fd;
char shm_name[PATH_MAX+] = "/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 + , name, PATH_MAX + ); fd = open (shm_name, oflag, mode); if (fd != -)
{
/* once open we must add FD_CLOEXEC flag to file descriptor */
int flags = fcntl (fd, F_GETFD, ); if (flags >= )
{
flags |= FD_CLOEXEC;
flags = fcntl (fd, F_SETFD, flags);
} /* on failure, just close file and give up */
if (flags == -)
{
close (fd);
fd = -;
}
} 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> int
shm_unlink (const char *name)
{
int rc;
char shm_name[PATH_MAX+] = "/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 + , name, PATH_MAX + ); rc = unlink (shm_name); return rc;
}
这也只是一个普通的unlink函数。也就是说,POSIX标准的共享内存就是一个文件。所谓的“一个进程删除本身打开的共享内存并不影响另一个进程的共享内存”就相当于你用fstream对象打开了一个文件,然后去文件夹把文件删除了(也就是对文件进行了unlink操作),可是fstream对象还可以正常读写文件,并没有什么引用计数。这下好了,进程退出时又没法同步了。
不过,在linux下怎么会有解决不了的问题呢?解决不了只能说明自己太菜。既然是文件,那就从文件下手。那文件有什么是原子操作,又可以计数的呢。答案:硬链接。比如:
xzc@xzc-HP-ProBook-4446s:/dev/shm$ stat abc
文件:"abc"
大小: 块: IO 块: 普通文件
设备:15h/21d Inode: 硬链接:
权限:(/-rw-rw-r--) Uid:( / xzc) Gid:( / xzc)
最近访问:-- ::00.961053098 +
最近更改:-- ::00.961053098 +
最近改动:-- ::00.961053098 +
创建时间:-
xzc@xzc-HP-ProBook-4446s:/dev/shm$
这个硬链接可以通过fstat函数获取。可是要这样实现的话,意味着需要先创建一块共享内存,每个进程引用的时候需要调用link函数来创建一个硬链接。问题解决了,可是这样会在/dev/shm下多个N多个文件。这可是RAM啊,虽然现在的服务器都比较牛,但这样做也不太好吧。好吧,还有一个flock文件锁。flock使用LOCK_SH参数多个进程对同一个文件加锁。这样,进程B初始化共享内存时加锁(可以有多个这样的进程),在退出(包括异常退出)时解锁。进程A在退出时检测这个锁。当发现无锁时说明可以安全退出了。
同步退出的问题基本解决了。来不及写代码去验证,下次吧。
PS:内核unlink时应该也是有计数才知道当前有没有进程打开文件,在什么时候应该删除文件。这个还得去查资料,看用不用得上。另外lsof这个工具是可以检测到所有打开该共享内存的进程及相应的状态。这个应该也是有对应的api的,只是现在还没搞懂。
linux使用共享内存通信的进程同步退出问题的更多相关文章
- linux 两个进程通过 共享内存 通信例子
例子1:两个进程通过共享内存通信,一个进程向共享内存中写入数据,另一个进程从共享内存中读出数据 文件1 创建进程1,实现功能,打印共享内存中的数据 #include <stdio.h> # ...
- linux下共享内存mmap和DMA(直接访问内存)的使用 【转】
转自:http://blog.chinaunix.net/uid-7374279-id-4413316.html 介绍Linux内存管理和内存映射的奥秘.同时讲述设备驱动程序是如何使用“直接内存访问” ...
- Linux进程间通信—共享内存
五.共享内存(shared memory) 共享内存映射为一段可以被其他进程访问的内存.该共享内存由一个进程所创建,然后其他进程可以挂载到该共享内存中.共享内存是最快的IPC机制,但由于linux本身 ...
- linux 下共享内存
一.共享内存相关知识 所谓共享内存,就是多个进程间共同地使用同一段物理内存空间,它是通过将同一段物理内存映射到不同进程的 虚拟空间来实现的.由于映射到不同进程的虚拟空间中,不同进程可以直接使用,不需要 ...
- linux 进程间通信 共享内存 mmap
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式.两个不同进程A.B共享内存的意思是,同一块物理内存被映射到进程A.B各自的进程地址空间.进程A可以即时看到进程B对共享内存中数据的更新,反 ...
- PHP进程通信基础——信号量+共享内存通信
PHP进程通信基础--信号量+共享内存通信 由于进程之间谁先执行并不确定,这取决于内核的进程调度算法,其中比较复杂.由此有可能多进程在相同的时间内同时访问共享内存,从而造成不可预料的错误.信号量这个名 ...
- Windows进程间共享内存通信实例
Windows进程间共享内存通信实例 抄抄补补整出来 采用内存映射文件实现WIN32进程间的通讯:Windows中的内存映射文件的机制为我们高效地操作文件提供了一种途径,它允许我们在WIN32进程中保 ...
- Linux IPC 共享内存
共享内存 共享内存(shared memory)是最简单的Linux进程间通信方式之一. 使用共享内存,不同进程可以对同一块内存进行读写. 由于所有进程对共享内存的访问就和访问自己的内存空间一样,而不 ...
- linux 进程间通信 共享内存 shmat
系统调用mmap()通过映射一个普通文件实现共享内存.系统V则是通过映射特殊文件系统shm中的文件实现进程间的共享内存通信.也就是说,每个共享内存区域对应特殊文件系统shm中的一个文件(这是通过shm ...
随机推荐
- animation之translate、scale、alpha、rotate动画效果呈现
动画类型 Android的animation由四种类型组成 XML中 alpha 渐变透明度动画效果 scale 渐变尺寸伸缩动画效果 translate 画面转换位置移动动画效果 rotate 画面 ...
- Beyond Compare 忽略两个文件内容的顺序比较文件内容(xjl456852原创)
有时两个文件内容的顺序是不固定的,对比时需要忽略文件顺序进行对比. 可以这样设置: 点击菜单下面工具栏按钮: 点击Format旁的三角,选择Sorted,就会按文件的顺序排序比较.忽略了文件内容顺序的 ...
- Collections.sort()
Comparator是个接口,可重写compare()及equals()这两个方法,用于比价功能:如果是null的话,就是使用元素的默认顺序,如a,b,c,d,e,f,g,就是a,b,c,d,e,f, ...
- (转)iOS Wow体验 - 第七章 - 操作图例与触屏人机工学
本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第七章译文精选,其余章节将陆续放出.上一篇:Wow ...
- vmplayer中的fedora20无法进入图形界面
新装了台fedora20的虚拟机,安装升级了一些东西后.启动时过了fedora的logo画面后就是黑屏. 也没提示不论什么错误,好在shell还能进去.查看/var/log/anaconda/sysl ...
- 【InversionCount 逆序对数 + MergeSort】
Definition of Inversion: Let (A[0], A[1] ... A[n], n <= 50) be a sequence of n numbers. If i < ...
- Swift自适应布局(Adaptive Layout)教程(二)
给TextContainer中添加内容 打开 Main.storyboard ,从组件库(Object Library)中拖拽两个 Label 组件到TextContainer中,位置可以随意摆放: ...
- UVA11388 GCD LCM1 2 -1
题目: 给你两个数G和L,求a和b,他们的最大公约数为G和最小公倍数为L,输出a最小时的a和b.如果不存在在输出-1. Sample Input 2 1 2 3 4 Output for Samp ...
- ASP.NET优化性能方法之一禁用调试模式(转)
若要设置 ASP.NET 应用程序的调试模式,必须编辑应用程序的 Web.config 配置文件. 通常,ASP.NET 应用程序的 Web.config 文件与应用程序位于相同的 URL 位置上. ...
- (转)[老老实实学WCF] 第一篇 Hello WCF
http://blog.csdn.net/songyefei/article/details/7363296#comments 老老实实学WCF 第一篇 Hello WCF WCF(Windows ...