使用信号量和共享内存实现进程间通信

来源:互联网 发布:学而知不足 编辑:程序博客网 时间:2024/05/29 17:40

共享内存是运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间复制。通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。共享内存往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥

使用共享存储来实现进程间通信的注意点是对数据存取的同步,必须确保当一个进程去读取数据时,它所想要的数据已经写好了。通常,信号量被要来实现对共享存储数据存取的同步,另外,可以通过使用shmctl函数设置共享存储内存的某些标志位如SHM_LOCK SHM_UNLOCK等来实现

sem shm 是独立的,只是程序之间的一种约定。譬如 
sem  -> /app1/sem1 
shm  -> /dev/shm/app1_shm1

所谓信号量和共享内存间的联系,是应用程序为了利用信号量的互斥特性保证共享内存并发访问的安全而利用定义的,只是逻辑上的联系,而非物理的

在访问共享内存前,首先试图去获得一个信号量旗标。如果成功,本进/线程就获得了对共享内存的访问权,在释放信号量旗标前其他进/线程无法获得该旗标,接下来本过程就可以对内存进行读写等操作。在共享内存使用完毕后,本进/线程释放旗标,其他进/线程又可以成功获取该信号量旗标

/*server.c:向共享内存中写入People*/

#include <stdio.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

 

int main()

{

        struct People{

               char name[10];

               int age;

        };

       

        int semid;

        int shmid;

        key_t semkey;

        key_t shmkey;

        semkey=ftok("server.c",0);

        shmkey=ftok("client.c",0);

       

        /*创建共享内存和信号量的IPC*/

        semid=semget(semkey,1,0666|IPC_CREAT);

        if(semid==-1)

        printf("creat sem is fail\n");

        shmid=shmget(shmkey,1024,0666|IPC_CREAT);

        if(shmid==-1)

        printf("creat shm is fail\n");

       

        /*设置信号量的初始值,就是资源个数*/

        union semun{

               int val;

               struct semid_ds *buf;

               ushort *array;

        }sem_u;

       

        sem_u.val=1;

        semctl(semid,0,SETVAL,sem_u);

       

        /*将共享内存映射到当前进程的地址中,之后直接对进程中的地址addr操作就是对共享内存操作*/

       

        struct People * addr;

        addr=(struct People*)shmat(shmid,0,0);

        if(addr==(struct People*)-1)

        printf("shm shmat is fail\n");

       

        /*信号量的P操作*/

        void p()

        {

               struct sembuf sem_p;

               sem_p.sem_num=0;

               sem_p.sem_op=-1;

               if(semop(semid,&sem_p,1)==-1)

               printf("p operation is fail\n");             

        }

 

        /*信号量的V操作*/

        void v()

        {

               struct sembuf sem_v;

               sem_v.sem_num=0;

               sem_v.sem_op=1;

               if(semop(semid,&sem_v,1)==-1)

               printf("v operation is fail\n");

        }

       

        /*向共享内存写入数据*/

        p();

        strcpy((*addr).name,"xiaoming");

/*注意:①此处只能给指针指向的地址直接赋值,不能在定义一个  struct People people_1;addr=&people_1;addraddr=(struct People*)shmat(shmid,0,0);,经由系统自动分配了一个地址,这个地址与共享内存相关联,所以不能改变这个指针的指向,否则他将不指向共享内存,无法完成通信了。

注意:②给字符数组赋值的方法。*/

        (*addr).age=10;

        v();

       

        /*将共享内存与当前进程断开*/

        if(shmdt(addr)==-1)

        printf("shmdt is fail\n");    

       

}

 

 

 

/*client.c:从共享内存中读出People*/

#include <stdio.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

 

int main()

{

        int semid;

        int shmid;

        key_t semkey;

        key_t shmkey;

        semkey=ftok("server.c",0);

        shmkey=ftok("client.c",0);

       

        struct People{

               char name[10];

               int age;

        };

 

        /*读取共享内存和信号量的IPC*/   

        semid=semget(semkey,0,0666);

        if(semid==-1)

        printf("creat sem is fail\n");

        shmid=shmget(shmkey,0,0666);

        if(shmid==-1)

        printf("creat shm is fail\n");

       

        /*将共享内存映射到当前进程的地址中,之后直接对进程中的地址addr操作就是对共享内存操作*/

        struct People * addr;

        addr=(struct People*)shmat(shmid,0,0);

        if(addr==(struct People*)-1)

        printf("shm shmat is fail\n");

       

        /*信号量的P操作*/

        void p()

        {

               struct sembuf sem_p;

               sem_p.sem_num=0;

               sem_p.sem_op=-1;

               if(semop(semid,&sem_p,1)==-1)

               printf("p operation is fail\n");             

        }

       

        /*信号量的V操作*/

        void v()

        {

               struct sembuf sem_v;

               sem_v.sem_num=0;

               sem_v.sem_op=1;

               if(semop(semid,&sem_v,1)==-1)

               printf("v operation is fail\n");

        }

       

        /*从共享内存读出数据*/

        p();

        printf("name:%s\n",addr->name);

        printf("age:%d\n",addr->age);

        v();

       

        /*将共享内存与当前进程断开*/

        if(shmdt(addr)==-1)

        printf("shmdt is fail\n");

       

        /*IPC须显示删除。否则会一直留存在系统中*/

        if(semctl(semid,0,IPC_RMID,0)==-1)

        printf("semctl delete error\n");

        if(shmctl(shmid,IPC_RMID,NULL)==-1)

        printf("shmctl delete error\n");

}

0 0
原创粉丝点击