posts - 15,comments - 21,trackbacks - 0
进程间通信方式包括了管道,消息队列,FIFO,共享内存,而共享内存是其中效率最高的。下图解释了其效率最高的原因(图片截取自《UNIX网络编程》)

我们可以看到上面的拷贝次数是4次,下面则是2次。
接下来我们看看使用,其实网上和书上都有了很多资料,API就是那么几个。
int shmget(key_t key,size_t size,int shmflag)。
key:可以指定IPC_PRIVATE,那么系统会为你创建一个key,并且返回一个id号。也可以通过ftok函数生成一个key(不了解ftok的童鞋可以动手man一下)。那么为什么要一个IPC既要一个key又有一个ID呢。这里我觉得是为了方便其他进程访问。进程A创建了一个共享内存,内核为其分配一个ID,这个时候进程B想要访问,他怎么获取这个ID(难道需要A把ID发送给B??)。但是我们用一个key就很方便了。事先A,B进程都知道这个key,那么A创建了,B就可以通过事先知道key找到这块内存。
size:共享内存的大小。如果是获得一块内存,则该值应该为0。
shmflag:读写权限的组合,可以与IPC_CREAT和IPC_EXCL按位或。当指定一个key时,IPC_CREAT和IPC_EXCL配合使用可以在存在该key的共享内存时返回-1。
当该函数调用成功后,返回一个系统分配的共享内存,并且size大小的字节被初始化为0

void *shmat(int shmid, const void *shmaddr, int shmflg)
有了一块共享内存后,进程需要映射该内存到进程的地址空间。这个函数就是作用。
shmid就是之前获得ID,shmaddr如果指定了,就会配合shmflg确定映射地址,不过一般都不这么干的。返回值就是获得的地址,你可以往里面写你或者读你需要的数据了。同时调用了该函数,系统会修改shmid_ds数据。

int shmdt(const void *shmaddr)
解除绑定关系,参数就是我们之前获取的那个返回地址。(其实我觉得这里参数如果为ID貌似更统一些吧)

int shmctl(int shmid, int cmd, struct shmid_ds *buf)
这个函数主要做一些修改和查询。比如设置锁,解锁,移除一块共享内存。

简单介绍了API,还要说一下一些注意的东西
1.共享内存不会把数据写入磁盘文件中,这个区别于mmap
2.即使没有进程绑定在共享内存,共享内存也不会消失的。必须通过shmctl或者ipcrm删除(或者更暴力的方式关掉电脑)

另外我们可能会考虑,系统最多创建多少个共享内存,一个进程最多可以绑定多少个内存,一个共享内存创建的size最大最小值是多少。其实这些设置在/proc/sys/kernel下面,我们也可以自己写程序来读取。贴一段代码用来获取上面的信息
#define MAX_SHMIDS        8196

int main(int argc,char *argv[])
{
    int i,j;
    int shmid[MAX_SHMIDS] = {0};
    void *addr[MAX_SHMIDS] = {0};
    
    //测试可以创建多少个共享内存
    for ( i = 0;i < MAX_SHMIDS;++i )
    {
        shmid[i] = shmget(IPC_PRIVATE,1024,0666|IPC_CREAT);
        if ( shmid[i] == -1 )
        {
            printf("create shared memory failed,max create num[%d],%s\r\n",i,strerror(errno));
            break;
        }
    }
    
    for ( int j = 0;j < i;++j )
    {
        shmctl(shmid[j],IPC_RMID,NULL);
    }
    
    //测试每个进程可以attach的最大数
    for ( i = 0;i < MAX_SHMIDS;++i )
    {
        shmid[i] = shmget(IPC_PRIVATE,1024,0666|IPC_CREAT);
        if ( shmid[i] != -1 )
        {
            addr[i] = shmat(shmid[i],0,0);
            if ( addr[i] == (void *)-1 )
            {
                printf("process attach shared memory failed,max num[%d],%s\r\n",i,strerror(errno));
                shmctl(shmid[i],IPC_RMID,NULL);
                break;
            }
        }
        else
        {
            printf("max num of process attach shared memory is[%d]\r\n",i-1);
            break;
        }
    }
    
    for ( j = 0;j < i;++j )
    {
        shmdt(addr[j]);
        shmctl(shmid[j],IPC_RMID,NULL);
    }
    
    //测试一个共享内存创建最小的size
    size_t size = 0;
    for ( ;;size++ )
    {
        shmid[0] = shmget(IPC_PRIVATE,size,0666|IPC_CREAT);
        if ( shmid[0] != -1 )
        {
            printf("create shared memory succeed,min size[%d]\r\n",size);
            shmctl(shmid[0],IPC_RMID,NULL);
            break;
        }
    }
    
    //测试共享内存创建最大的size
    for ( size = 65536;;size += 1024 )
    {
        shmid[0] = shmget(IPC_PRIVATE,size,0666|IPC_CREAT);
        if ( shmid[0] == -1 )
        {
            printf("create shared memory failed,max size[%ld],%s\r\n",size,strerror(errno));
            break;
        }
        
        shmctl(shmid[0],IPC_RMID,NULL);
    }
    
    exit(0);
}
好了,下篇开始介绍如何控制读写。
posted on 2012-09-06 19:26 梨树阳光 阅读(1984) 评论(0)  编辑 收藏 引用 所属分类: Linux

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理