linux 进进程间通信(IPC) 之共享内存

共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。这是因为所有进程共享同一块内存,共享内存在各种

进程间通信方式中具有最高的效率。访问共享内存区域和访问进程独有的内存区域一样快,并不需要通过系统调用或者其

它需要切入内核的过程来完成。同时它也避免了对数据的各种不必要的复制。例如 两个不同进程A、B共享内存的意思是,

同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。

由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以

其中有关共享内存的一些基本的定义请重点参见 共享模型、绑定、脱离 :linux共享内存


共享内存实现步骤:


     1、创建共享内存:shmget函数;
           int shmget(key_t key,int size,int shmflg)
              key:
 数据类型key_t是在头文件sys/types.h中定义的,它是一个长整形的数据。

                     我们可以利用 ftok()函数创建key, 当成功执行的时候,一个key_t值将会被返回,否则-1被返回。我们可以使用,

                     strerror(errno)来确定具体的错误信息。                     

             size:共享内存大小
           返回值:成功则返回共享内存标识符;失败返回-1;

     2、映射共享内存(连接到自身的地址空间中):shmat函数;
          int shmat(int shmid,char* shmaddr,int flag)
            shmid:返回的共享存储标识符;
            shmaddr:共享内存在进程中的地址,不同进程这个地址不一样,通常设为0;
            flag:决定以什么方式来确定映射的地址(通常为0);
          返回值:成功返回共享内存映射到进程中的地址;失败返回-1;
     3、解除映射:shmdt
          int shmdt(char *shmaddr)
          不需要共享内存时,需要把它从进程地址空间中脱离;

     4、控制释放:shmctl

         int shmctl( int shmid , int cmd , struct shmid_ds *buf );

          int shmid是共享内存的ID。
          int cmd是控制命令,可取值如下:
             IPC_STAT        得到共享内存的状态
             IPC_SET         改变共享内存的状态
             IPC_RMID        删除共享内存
             struct shmid_ds *buf是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。

             如果要改变共享内存的状态,用这个结构体指定。
         返回值: 成功:0 失败:-1


   下面我们举一个例子,下面的代码在父进程和子进程之间利用共享内存进行通信,父进程向共享内存中写入数据,

   子进程读取数据。两个进程之间的控制采用了信号量的方法,父进程写入数据成功后信号量加1.子进程在访问信号

   量之前先等待信号。  

       

// ipc_shm.c
#include <stdio.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <string.h>

typedef int sem_t;
union semun {// 信号量操作的联合结构
 int val;
 struct semid_ds *buf;
 unsigned short *array;
} arg;
sem_t CreateSem(key_t key, int value)// 建立信号量, 键值key 及信号量的初始值value
{
	union semun sem;
	sem_t semid; // 信号量ID
	sem.val = value;
	
	semid = semget(key,value,IPC_CREAT|0666); //获得信号量ID
	if (-1 == semid)
	{
		printf("create semaphore error\n");
		return -1;
	}
	
	semctl(semid,0,SETVAL,sem);// 发送命令,建立value个初始值的信号量
	
	return semid;
}
/*
struct sembuf{
	ushort sem_num;
	short  sem_op;
	short  sem_flg;
};
*/
void SetvalueSem(sem_t semid, int value)// 设置信号量的值
{
	union semun sem;
	sem.val = value;
	semctl(semid,0,SETVAL,sem);
	return ;
}

int GetvalueSem(sem_t semid)// 获得信号量的值
{
	union semun sem;
	return semctl(semid,0,GETVAL,sem);
}

void DestroySem(sem_t semid)// 销毁信号量
{
	union semun sem;
	sem.val = 0;
	semctl(semid,0,IPC_RMID,sem);
}

int Sem_P(sem_t semid)// 增加信号量
{
	struct sembuf sops={0,+1,IPC_NOWAIT}; // 建立信号量结构值
	return (semop(semid,&sops,1));// 发送命令
}

int Sem_V(sem_t semid)//减少信号量值
{
	struct sembuf sops={0,-1,IPC_NOWAIT};// 建立信号量结构值
	return (semop(semid,&sops,1));
}

static char msg[]="你好,共享内存\n";

int main(void)
{
	key_t key;
	int semid,shmid;
	char i,*shms,*shmc;
	struct semid_ds buf;
	int value = 0;
	char buffer[80];
	pid_t p;
	
	key = ftok("./ipc_shm.c", 0);// 生成键值
	shmid = shmget(key,1024,IPC_CREAT|0604);
	
	semid = CreateSem(key,0);// 0 ? 1
	
	p = fork();
	if(p > 0)// 父进程
	{
		/* 父进程 */
		/* 建立共享内存 */
		shms = (char *)shmat(shmid,0,0);// 挂接共享内存
		
		memcpy(shms, msg, strlen(msg)+1);// 赋值内容	
		sleep(2);
		Sem_P(semid);// 获得共享内存的信号量
		shmdt(shms);// 摘除共享内存
				
		DestroySem(semid);// 销毁信号量
	}
	else if(p == 0)
	{
		shmc = (char *)shmat(shmid,0,0);// 挂接共享内存
		Sem_V(semid);// 减少信号量
		printf("共享内存的值为:%s\n",shmc);// 
		shmdt(shmc);
	}
      if(shmctl(shmid,IPC_RMID,NULL)==-1)  
         printf("shmctl delete error\n");
return 0;
//gcc -o shm icp_shm.c -g
}

 在 ubuntu 下sleep时貌似信号量直接跳过,后再休眠。等待下一步实验


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值