Linux 进程通讯(共享内存区)

共享内存是由内核出于在多个进程间交换信息的目的而留出的一块内存区(段)。
若是段的权限设置恰当,每一个要访问该段内存的进程均可以把它映像到本身的私有地址空间中。
若是一个进程更新了段中的数据,其余进程也当即会看到更新。
由一个进程建立的段,也能够由另外一个进程读写。
每一个进程都把它本身对共享内存的映像放入本身的地址空间。
建立共享内存区
int shmget(key_t key,size_t size,int shm-flg);
参数key既能够是IPC_PRIVATE(IPC_PRIVATE表示让系统分配一个Key),也能够是ftok函数返回的一个关键字。
参数size指定段的大小。
参数flgs--八进制数,0666,转化为二进制后分别表明rw-rw-rw-
shmget成功返回段标识符,失败返回-1(通常不会建立失败,除非系统没有内存).
注意:只有建立权限是0666的才能够用命令行"ipcs -m"查看,其余类型权限的共享内存区没法被这个命令所查看。
//建立共享内存
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <sys/ipc.h>
#include <sys/shm.h>

int main(int arg, char *args[])
{
    int shmid=shmget(IPC_PRIVATE,sizeof(char)*1024,0666);
    if(shmid==-1)
    {
        printf("error\n");
        return -1;
    }
    printf("建立共享内存成功!内存段标识符是%d\n",shmid);
    return 0;
}
在命令行执行"ipcs -m "显示已经成功的建立了一块共享内存区。
nattch字段显示已经附加到这个内存区的进程数。

 

附加共享内存区
void * shmat(int shmid,void * shmaddr,int shmflg);
int shmdt(const * void shmaddr);
参数shmid是要附加的共享内存区标识符(在命令行执行ipcs -m 显示)。
老是把参数shmaddr设为0,0表示系统会自动在被附加的进程内建立一个内存段,映射到共享内存区。固然也能够指定一个被附加的进程内的一块内存,可是须要用户本身malloc分配内存,并将地址传给shmaddr参数,比较麻烦,通常使用系统自动分配。
参数shmflg能够为SHM_RDONLY,这意味着附加段是只读的,参数为0时,表示能够读写。
shmat成功返回被附加了段的地址,失败返回-1,并设置errno,虽然返回值是指针类型,可是返回的的确是-1。
函数shmdt是将附加在shmaddr的段从调用进程的地址空间分离出去,这个地址必须是shmat返回的(即从本身进程内释放被附加的共享内存,强调不是释放系统的那个共享内存)。
注意:进程里附加共享内存区的大小必定是和系统共享内存同样大,为了方便映射(两块内存不同大如何同步数据?)。
//建立附加共享内存
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/shm.h>

int main(int arg, char *args[])
{
    if (arg < 3)
    {
        printf("请输入2个参数!\n");
        return -1;
    }
    int flag = 0;
    int shmid = 0;
    shmid = atoi(args[1]);
    flag = atoi(args[2]);
    //建立本进程被附加的共享内存
    void * shmbuf = NULL;
    shmbuf = shmat(shmid, 0, 0);
    /*
     编译警告:warning: cast from pointer to integer of different size
     这句警告意思是指针类型大小和Int类型大小不一样,根据之前的知识,指针都是4个字节大小,
     其实指针的大小不是固定的4个字节。32位cpu的计算机上是4字节,64位cpu的计算机上是8个字节。
     这是由于32位计算机中的地址是32位的(能够在32位系统下查看指针的值例如--0x003bf9a3)
     可是在64位计算机中地址是64位的(能够在64位系统下查看指针的值例如--0xffffffffffffffff)
     十六进制数字的1位等于二进制的4位
     虽然指针的值在32位系统和64位系统中有区别,可是一个字节的大小在两个系统中是相同的,
     举例说Int类型数据,无论是在32位系统和64位系统中都在内存中占据4个字节大小的内存空间
     */
    if ((int) shmbuf == -1)
    {
        printf("建立附加共享内存区失败!error message:%s\n", strerror(errno));
        return -1;
    }
    sleep(10);
    if (flag == 1)
    {
        //将数据写入本进程本身的附加共享内存区
        //这里系统共享内存区的大小是1kb
        read(STDIN_FILENO, shmbuf, sizeof(char) * 1024);
    } else if (flag == 2)
    {
        printf("%s", shmbuf);
    }
    return 0;
}
shmdt函数
--功能:将共享内存段与当前进程脱离
--参数
    shmarr:由shmat所返回的指针
--返回值:成功返回0,失败返回-1
--注意:将共享内存段与当前进程脱离不等于删除共享内存

 

释放共享内存区
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数shmid是共享内存区段标识符,
参数cmd通常有三个值IPC_STAT(获取共享内存区的状态,由第三个参数获取状态),IPC_SET(设置共享内存区),IPC_RMID(删除共享内存区,此时第三个参数通常传0);
shmctl成功返回0,失败返回-1,而且设置errno的值
//建立共享内存区
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(int arg,char * args[])
{
    if(arg<2)
    {
        printf("请输入一个参数!\n");
        return -1;
    }
    int shmid=atoi(args[1]);
    int flag=shmctl(shmid,IPC_RMID,0);
    if(flag<0)
    {
        printf("error message:%s\n",strerror(errno));
        return -1;
    }
    printf("返回值是%d\n",flag);
    return 0;
}
命令行释放共享内存区
在命令行执行"ipcrm -m shmid" 或者 "ipcrm shm shmid"
相关文章
相关标签/搜索