进程通信之IPC通信对象——共享内存

IPC通信------IPC对象:1,共享内存,2,消息队列3,信号灯。
IPC对象

1,共享内存


例子1,利用shmget()函数创建共享内存;
建立shmid.c文件,内容如下

#include"system/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
int main()
{
    int shmid;
    //create shared memory
    shmid=shmget(IPC_PRIVATE,128,0777);
    if(shmid<0)
    {
    printf("create shared memory failure\n");
    return   -1;
    }
    printf("reate shared memory success\n");
    system("ipc -m");//查看共享的系统内存
    //system("ipc -m shmid");//删除共享内存
    return 0;
}

运行编译:gcc -o shimd shmid.c
生成执行文件shmid,再运行./shimd,r如下图成功创建shmid为1802250,权限为777,大小为128的共享内存;

再运行命令:ipcrm -m 1802250就可以释放该内存,如下图。

【注】shmget()通过IPC_PRIVATE宏所创建的key,全为0,实现的是亲缘进程间的通信;

因此可采用ftork(函数)创建key值;

例子2:ftork()创建key值,建立文件ftok.c和cp.c(任意创建的文件)。ftok.c内容如下:

#include"system/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
int main()
{
    int shmid;
    int key;
    key=ftork("./p.c",'p');
    if(key<0)
    {
        printf("create key failure\n");
        return -2;
     }
     printf("create key sucess key=%x\n",key);
     //create shared memory
     shmid=shmget(key,128,IPC_CREAT | 0777);//以ftork()创建的key作为要创建的共享内存的key
    if(shmid<0)
    {
    printf("create shared memory failure\n");
    return   -1;
    }
    printf("reate shared memory success\n");
    system("ipc -m");//查看共享的系统内存
    //system("ipc -m shmid");//删除共享内存
    return 0;
}

编译运行:./ftok

可以通过修改ftok()函数的第二参数值来创建不同的key值,ftok实现非亲缘关系进程之间的通信。

由于shmget()函数所创建的共享内存在内核空间,进程间同过共享内存通信,每次都要调用write(),read()等系统函数,非常麻烦。所有引入shmat函数,该函数可以将内核的共享内存印射到用户空间,从而实现两个进程之间通信时可以不用每次通信都经过内核。

例子3:shmat的用法,建立shmat.c文件,内容如下:

#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
int main()
{
    int shmid;
    int key;
    char *p;
    key=ftok("./p.c",'p');
    if(key<0)
    {
        printf("create key failure\n");
        return -2;
     }
     printf("create key sucess key=%x\n",key);
     //create shared memory
     shmid=shmget(key,128,IPC_CREAT | 0777);//以ftork()创建的key作为要创建的共享内存的key
    if(shmid<0)
    {
    printf("create shared memory failure\n");
    return   -1;
    }
    printf("reate shared memory success\n");
    
    p=(char*)shmat(shmid,NULL,0);//印射创建的共享内存到内核用户空间
    if(p==NULL)
        {
        printf("shmat function failure\n");
        return -3;
        }
        //write something to share memory
         fgets(p,128,stdin);//从标准输入写入共享内存
        
        //read to stdout
        printf("first shared memory =");//第一次读取
        fputs(p,stdout);
        printf("\nsecond shared memory =");//第二次读取共享内存的内容
        fputs(p,stdout);//从共享内存读出到标准输出
        
    system("ipcs -m");//查看共享的系统内存
    return 0;
}

运行结果:

共享内存可以多次读取,里面的信息不会被删除。

例子4:将共享内存空间印射到用户空间的地址删除;shmdt()函数的应用。建立shmdt.c文件,内容基于例子3,添加两行代码,
shmdt(p);//释放用户空间印射的地址
mecpy(p,"hello",5);//释放后再向该地址写东西时,会发生段错误。
如下;

#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
int main()
{
    int shmid;
    int key;
    char *p;
    key=ftok("./p.c",'p');
    if(key<0)
    {
        printf("create key failure\n");
        return -2;
     }
     printf("create key sucess key=%x\n",key);
     //create shared memory
     shmid=shmget(key,128,IPC_CREAT | 0777);//以ftork()创建的key作为要创建的共享内存的key
    if(shmid<0)
    {
    printf("create shared memory failure\n");
    return   -1;
    }
    printf("reate shared memory success\n");
    
    p=(char*)shmat(shmid,NULL,0);//印射创建的共享内存到内核用户空间
    if(p==NULL)
        {
        printf("shmat function failure\n");
        return -3;
        }
        //write something to share memory
         fgets(p,128,stdin);//从标准输入写入共享内存
        
        //read to stdout
        printf("first shared memory =");//第一次读取
        fputs(p,stdout);
        printf("\nsecond shared memory =");//第二次读取共享内存的内容
        fputs(p,stdout);//从共享内存读出到标准输出
    system("ipcs -m");//查看共享的系统内存
    shmdt(p);//释放用户空间印射的地址
    mecpy(p,"hello",5);//释放后再向该地址写东西时,会发生段错误。
    return 0;
}

运行结果如下:

shmctl()函数分析:
75c645b5e0904621407f0a5827dd7f33.png
如图上,用户印射地址被释放。接下来再用shmctl()函数释放内核的共享内存地址,基于例4,再return 0;前加入
shmctl(shmid,IPC_RMID,NULL);//free kernel shared memory
system("ipcs -m");//释放内核共享内存后,查看共享内存是否还在

结果是:共享内存分配后,调用shmctl()函数将其又释放了。

【注意】删除共享内存时,shmctl()的第二个参数为RMID,第三个参数可以设置为NULL,当第二个参数为IPC_SET,IPC_STAT时,第三个参数才要设置。

例子5:利用shmctl()函数实现共享内存的删除命令:ipcrm -m shmid
建立ipcrm.c,内容如下:

#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
int main(int argc,char *argv[])
{
    if(argc<3)
    {
    printf("please input 3 param\n");
    return -1;
    }
    if(strcmp(argv[1],"m") ==0)
    {
        printf("delete shared memory");
     }
     else
     {
     return -2;
     }
    int shmid;
    shmid=atoi(argv[2]);//获取用户输入shmid
    printf("shmid=%d\n",shmid);
    shmctl(shmid,IPC_RMID,NULL);
    system("ipcrm -m ");
   
   return 0;
}

运行编译命令:gcc -o ipcrm ipcrm.c
生成ipcrm执行文件,此时运行:./ipcrm -m shmid 就等价于ipcrm -m shmid

父子进程之间及非亲缘进程之间的通信,具体体现ftok()函数的key,IPC_PRAVITE的区别
综合实例1:用共享内存实现主进程A和子进程B之间的通信。

建立文件parent_child_communition.c,具体代码如下:

unition.c 
#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"

void myfun_parent(int signum)
{       
        printf("parent gets signal is %d\n",signum);    
        return;
}

void myfun_child(int signum)
{
        printf("child gets signal is %d\n",signum);
        return;
}
int main()
{
        pid_t pid;
        int shmid;
        char *p;
        shmid=shmget(IPC_PRIVATE,128,0777);//create shared memory
        if(shmid<0)
        {
        printf("create shared memory failure\n");
        return -1;
        }
        printf("create shared memory success\n");
        
        pid=fork();
        if(pid>0)//parent process code
        {
        signal(SIGUSR2,myfun_parent);
        p=(char*)shmat(shmid,NULL,0);//reflect the shared memory to usrmemory
        if(p==NULL)
        {
        printf("reflect the shared memory failure\n");
        return -2;
        }
        //reserve to write data to usrmemory 
        while(1)
        {
        printf("parent process start to write data to usrmemory\n");
        fgets(p,128,stdin);//get data from stdin
        kill(pid,SIGUSR1);//send to tell child process after data writed
        pause();//wait to child proces read
        }
        }

        if(pid==0)//child proces code
        {
        signal(SIGUSR1,myfun_child);//receive signal from parent process and jumb to myfun
        p=(char*)shmat(shmid,NULL,0);//relect shared memory to own
        if(p==NULL)
        {
        printf("reflect shared memory to child process failure\n");
        return -3;
        }
        while(1)
        {
        pause();//wait parent process write
        //start to read the shared memory
        printf("here is child,the data writed into shared memory are:%s\n",p);
        fputs(p,stdout);//read to standard output
        kill(getppid(),SIGUSR2);//then send SIGUSR2 to tell parent process
        }
        }
        shmdt(p);
        shmctl(shmid,IPC_RMID,NULL);
        return 0;
}

 

【注意】shmget()函数要在fork()函数之前,否则父子进程会分别创建出自己不同的共享内存,这样就无法进行通信了,因为父子进程通信要对同一个共享内存进行读写。

综合实例2:非亲缘进程之间的通信,菜用fork函数生成共享内存的非零key值。


建立server.c,client.c,f.c(无内容要求)文件

server.c代码如下:

#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
typedef struct buf{
        int pid;
        char shm_buf[124];
}BUF;

void myfun_A(int signum)
{
        printf("server gets signal is %d\n",signum);
        return;
}
int main()
{
        pid_t pid;
        int shmid;
        BUF *p;
        int key;
        key=ftok("./f.c",'f');
        if(key<0)
        {
        printf("create shmid's key failure\n");
        return -3;
        }
        printf("create shmid's key  success, key =%d\n",key);

        shmid=shmget(key,128,IPC_CREAT | 0777);//create shared memory
        if(shmid<0)
        {
        printf("create shared memory failure\n");
        return -1;
        }
        printf("create shared memory success\n");
        
        signal(SIGUSR2,myfun_A);
        p=(BUF*)shmat(shmid,NULL,0);//reflect the shared memory to usrmemory
        if(p==NULL)
        {
        printf("reflect the shared memory failure\n");
        return -2;
        }
        
        p->pid=getpid();//write A process pid to share memory
        
        pause();//wait B process read A process pid
        
        pid=p->pid;//read B process pid from shared memory
        //A process to write data to usrmemory 
        while(1)
        {
        printf("read the shared memory data writed by B process\n");
        fputs(p->shm_buf,stdout);//read to standard output
        if(strcmp(p->shm_buf,"shutdown\0")==0)break;
        printf("A process start to write data to  usrmemory\n");
        fgets(p->shm_buf,128,stdin);//get data from stdin
        kill(p->pid,SIGUSR1);//send signal to tell B process after data writed
        pause();//wait B process read
        }
        

        shmdt(p);
        shmctl(shmid,IPC_RMID,NULL);
        system("ipcs -m");
        return 0;
}

client.c代码如下:

#include"sys/types.h"
#include"sys/shm.h"
#include"signal.h"
#include"unistd.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
typedef struct buf{
        int pid;
        char shm_buf[124];
}BUF;

void myfun_B(int signum)
{
        printf("B process gets signal is %d\n",signum);
        return;
}
int main()
{
        pid_t pid;
        int shmid;
        BUF *p;
        int key;
        key=ftok("./f.c",'f');
        if(key<0)
        {
        printf("create shmid's key failure\n");
        return -3;
        }
        printf("create shmid's key success, key=%d\n",key);

        shmid=shmget(key,128,IPC_CREAT | 0777);//create shared memory
        if(shmid<0)
        {
        printf("create shared memory failure\n");
        return -1;
        }
        printf("create shared memory success\n");
        
        
        signal(SIGUSR1,myfun_B);
        p=(BUF*)shmat(shmid,NULL,0);//reflect the shared memory to usrmemory
        if(p==NULL)
        {
        printf("reflect the shared memory failure\n");
        return -2;
        }
        //get A process pid
        pid=p->pid;
        //write B process pid to shared memory
        p->pid=getpid();
        //send signal to A
        kill(pid,SIGUSR2);
        //B process start to read data from usrmemory 
        while(1)
        {
        pause();//wait A process to write data to shared memory
        printf("B process start to read data from usrmemory\n");
        fputs(p->shm_buf,stdout);//get data from stdin
        printf("write something to shared memory\n");
        fgets(p->shm_buf,128,stdin);//write to something to shared memory
        kill(pid,SIGUSR2);//send to tell B process after data writed
        }
        

        shmdt(p);
        shmctl(shmid,IPC_RMID,NULL);
        system("ipcs -m");
        return 0;
}

以上是进程间通过共享内存的通信总结。

发布了50 篇原创文章 · 获赞 13 · 访问量 1838

猜你喜欢

转载自blog.csdn.net/weixin_38251305/article/details/103935759