如何实现进程间通信

使用共享内存(物理内存)的步骤:

1、创建共享内存

2、映射到虚拟地址空间

3、把数据写到共享内存

4、解除映射并销毁

为避免同一时间多个进程访问同一内存,我们必须给共享内存加锁,实现进程同步。

加锁过程:

1、创建信号量

2、初始化信号量

3、进行p操作(拔钥匙)和v操作(插钥匙)

4、程序运行结束后销毁

代码段如下:

共享进程一:

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define SHMKEY   1234
#define SHMSIZE  4096       //以页为单位分配共享内存
#define SEMKEY   1234

union semun {
	int              val;    /* Value for SETVAL */
	struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
	unsigned short  *array;  /* Array for GETALL, SETALL */
	struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux specific) */
};

void sem_p(int semid)
{
	int ret;
	struct sembuf sbuf;

	sbuf.sem_num = 0;      //第一个 从0开始
	sbuf.sem_op = -1;      //p操作
	sbuf.sem_flg = SEM_UNDO;  

	ret = semop(semid, &sbuf, 1);
	if (-1 == ret)
	{
		perror("semop");
		return;
	}
}

void sem_v(int semid)
{
	int ret;
	struct sembuf sbuf;

	sbuf.sem_num = 0;      //第一个 从0开始
	sbuf.sem_op = 1;      //v操作
	sbuf.sem_flg = SEM_UNDO;  

	ret = semop(semid, &sbuf, 1);
	if (-1 == ret)
	{
		perror("semop");
		return;
	}
}

int main()
{
	int shmid, semid, ret;
	void *shmaddr;
	int count = 0;

	shmid = shmget(SHMKEY, SHMSIZE, IPC_CREAT | IPC_EXCL);   //创建共享内存
	if (-1 == shmid)
	{
		perror("shmget");
		exit(1);
	}

	semid = semget(SEMKEY, 1, IPC_CREAT | IPC_EXCL);    //创建信号量
	if (semid == -1)
	{
		perror("semget");
		exit(1);
	}

	union semun unsem;
	unsem.val = 1;    //初始化成二值信号量
	ret = semctl(semid, 0, SETVAL, unsem);    //初始化信号量
	if (-1 == ret)
	{
		perror("semctl");
		exit(1);
	}

	shmaddr = shmat(shmid, NULL, 0);    //映射到虚拟地址空间
	if (NULL == shmaddr)
	{
		perror("shmat");
		exit(1);
	}

	*(int *)shmaddr = count;       //数据写到共享内存

	while (1)
	{
		sem_p(semid);             //p操作  拔钥匙
		count = *(int *)shmaddr;     //读取数据
		usleep(100000);
		if (count >= 100)
		{
			break;
		}

		printf("Process A : count = %d\n", count);

		count++;

		*(int *)shmaddr = count;    //写回共享内存
		sem_v(semid);           //v操作  加一操作  插钥匙
	}

	shmdt(shmaddr);               //解除映射
	shmctl(shmid, IPC_RMID, NULL);

	semctl(semid, 0, IPC_RMID);
	return 0;
}

共享进程2:

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define SHMKEY   1234
#define SHMSIZE  4096       //以页为单位分配共享内存
#define SEMKEY   1234

union semun {
	int              val;    /* Value for SETVAL */
	struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
	unsigned short  *array;  /* Array for GETALL, SETALL */
	struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux specific) */
};

void sem_p(int semid)
{
	int ret;
	struct sembuf sbuf;

	sbuf.sem_num = 0;      //第一个 从0开始
	sbuf.sem_op = -1;      //p操作
	sbuf.sem_flg = SEM_UNDO;  

	ret = semop(semid, &sbuf, 1);
	if (-1 == ret)
	{
		perror("semop");
		return;
	}
}

void sem_v(int semid)
{
	int ret;
	struct sembuf sbuf;

	sbuf.sem_num = 0;      //第一个 从0开始
	sbuf.sem_op = 1;      //v操作
	sbuf.sem_flg = SEM_UNDO;  

	ret = semop(semid, &sbuf, 1);
	if (-1 == ret)
	{
		perror("semop");
		return;
	}
}

int main()
{
	int shmid, semid, ret;
	void *shmaddr;
	int count = 0;

	shmid = shmget(SHMKEY, SHMSIZE, 0);   //创建共享内存
	if (-1 == shmid)
	{
		perror("shmget");
		exit(1);
	}

	semid = semget(SEMKEY, 1, 0);    //创建信号量
	if (semid == -1)
	{
		perror("semget");
		exit(1);
	}

	shmaddr = shmat(shmid, NULL, 0);    //映射到虚拟地址空间
	if (NULL == shmaddr)
	{
		perror("shmat");
		exit(1);
	}

	while (1)
	{
		sem_p(semid);             //p操作  拔钥匙
		count = *(int *)shmaddr;     //读取数据
		usleep(100000);
		if (count >= 100)
		{
			break;
		}

		printf("Process B : count = %d\n", count);

		count++;

		*(int *)shmaddr = count;    //写回共享内存
		sem_v(semid);           //v操作  加一操作  插钥匙
	}

	shmdt(shmaddr);               //解除映射
	return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值