Linux进程间通信

本文深入讲解了进程间通信(IPC)的多种方式,包括管道通信(无名管道和有名管道)、共享内存、消息队列及信号量等。通过具体代码示例展示了每种通信方式的应用场景和技术细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 、管道通信

1 、无名管道

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

void ReadData(int fd)
{
	int ret;
	char buf[32] = {0};

	while (1)
	{
		ret = read(fd, buf, sizeof(buf));
		if (-1 == ret)
		{
			perror("read");
			exit(1);
		}

		if (!strcmp(buf, "bye"))
		{
			break;
		}

		printf("read from pipe : %s\n", buf);

		memset(buf, 0, sizeof(buf));
	}

	close(fd);
}

void WriteData(int fd)
{
	int ret;
	char buf[32] = {0};

	while (1)
	{
		scanf("%s", buf);

		ret = write(fd, buf, strlen(buf));
		if (-1 == ret)
		{
			perror("wirte");
			exit(1);
		}

		if (!strcmp(buf, "bye"))
		{
			break;
		}

		memset(buf, 0, sizeof(buf));
	}

	close(fd);
}

int main()
{
	int ret, fd[2] = {0};
	pid_t pid;

	ret = pipe(fd);   //创建一个无名管道
	if (-1 == ret)
	{
		perror("pipe");
		exit(1);
	}

	pid = fork();    
	if (-1 == pid)
	{
		perror("fork");
		exit(1);
	}
	else if (0 == pid)
	{
		close(fd[1]);       //关闭写端口
		ReadData(fd[0]);    //fd[0]读数据
	}
	else
	{
		close(fd[0]);       //关闭读端口
		int status;
		WriteData(fd[1]);   //fd[1]写数据

		wait(&status);
	}

	return 0;
}

2 、有名管道

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
	int ret, fd;
	char buf[32] = {0};    //管道写数据

	fd = open("fifo.tmp", O_WRONLY);
	if (-1 == fd)
	{
		perror("open");
		exit(1);
	}

	while (1)
	{
		scanf("%s", buf);
		ret = write(fd, buf, strlen(buf));
		if (-1 == ret)
		{
			perror("read");
			exit(1);
		}

		if (!strcmp(buf, "bye"))
		{
			break;
		}

		memset(buf, 0, sizeof(buf));
	}

	close(fd);

	return 0;
}

 

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
	int ret, fd;
	char buf[32] = {0};    //从管道读取数据

	ret = mkfifo("fifo.tmp", 666);  //创建有名管道
	if (ret == -1)
	{
		perror("mkfifo");
		exit(1);
	}

	fd = open("fifo.tmp", O_RDONLY);
	if (-1 == fd)
	{
		perror("open");
		exit(1);
	}

	while (1)
	{
		ret = read(fd, buf, sizeof(buf));
		if (-1 == ret)
		{
			perror("read");
			exit(1);
		}

		if (!strcmp(buf, "bye"))
		{
			break;
		}

		printf("%s\n", buf);

		memset(buf, 0, sizeof(buf));
	}

	close(fd);

	unlink("fifo.tmp");

	return 0;
}

 

二 、共享内存

1、申请共享内存   shmget

2、映射                  shmat

3、使用                  strcpy

4、解除映射           shmdt

5、销毁共享内存    shmctl

 

#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;
}

 

#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;
}

 

三 、消息队列

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#define MSGKEY   1234

struct msgbuf {
	long mtype;     /* message type, must be > 0 */
	char mtext[64];  /* message data */
};

int main()
{
	struct msgbuf mbuf;
	int ret;

	int msgid = msgget(MSGKEY, IPC_CREAT | IPC_EXCL);
	if (-1 == msgid)
	{
		perror("msgget");
		exit(1);
	}

	pid_t pid = fork();
	if (-1 == pid)
	{
		perror("fork");
		exit(1);
	}
	else if (0 == pid)    //子进程发送
	{
		while (1)
		{
			memset(&mbuf, 0, sizeof(mbuf));            //清零操作
	
			mbuf.mtype = 1;   //消息类型
			scanf("%s", mbuf.mtext);

			ret = msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
			if (-1 == ret)
			{
				perror("msgsnd");
				exit(1);
			}

			if (!strcmp(mbuf.mtext, "bye"))
			{
				mbuf.mtype = 2;
				msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
				break;
			}
		}
	}
	else                 //父进程接收
	{
		while (1)
		{
			memset(&mbuf, 0, sizeof(mbuf));
		
			ret = msgrcv(msgid, &mbuf, sizeof(mbuf.mtext), 2, 0);
			if (-1 == ret)
			{
				perror("msgrcv");
				exit(1); 
				
			}

			if (!strcmp(mbuf.mtext, "bye"))
			{	
				kill(pid, 2);
				break;
			}
			
			printf("\t\t\t%s\n", mbuf.mtext);

			memset(&mbuf, 0, sizeof(mbuf));
		}
	}

	sleep(1);
	msgctl(msgid, IPC_RMID, NULL);

	return 0;
}

 

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#define MSGKEY   1234

struct msgbuf {
	long mtype;     /* message type, must be > 0 */
	char mtext[64];  /* message data */
};

int main()
{
	struct msgbuf mbuf;
	int ret;

	int msgid = msgget(MSGKEY, 0);
	if (-1 == msgid)
	{
		perror("msgget");
		exit(1);
	}

	pid_t pid = fork();
	if (-1 == pid)
	{
		perror("fork");
		exit(1);
	}
	else if (0 == pid)    //子进程发送
	{
		while (1)
		{
			memset(&mbuf, 0, sizeof(mbuf));
	
			mbuf.mtype = 2;   //消息类型
			scanf("%s", mbuf.mtext);

			ret = msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
			if (-1 == ret)
			{
				perror("msgsnd");
				exit(1);
			}

			if (!strcmp(mbuf.mtext, "bye"))
			{
				mbuf.mtype = 1;
				msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
				break;
			}
		}
	}
	else                 //父进程接收
	{
		while (1)
		{
			memset(&mbuf, 0, sizeof(mbuf));
		
			ret = msgrcv(msgid, &mbuf, sizeof(mbuf.mtext), 1, 0);
			if (-1 == ret)
			{
				perror("msgrcv");
				exit(1);
			}

			if (!strcmp(mbuf.mtext, "bye"))
			{
				kill(pid, 2);
				break;
			}
			
			printf("\t\t\t%s\n", mbuf.mtext);

			memset(&mbuf, 0, sizeof(mbuf));
		}
	}

	return 0;
}

四 、信号量

  信号量(又名:信号灯)与其他进程间通信方式不大相同,主要用途是保护临界资源. 进程可以根据它判定是否能够访问某些共享资源。除了用于访问控制外,还可用于进程同步。

  二值信号灯:信号灯的值只能取0或1,类似于互斥锁。 但两者有不同: 信号灯强调共享资源,只要共享资源可用,其他进程同样可以修改信号灯的值; 互斥锁更强调进程,占用资源的进程使用完资源后,必须由进程本身来解锁。     计数信号灯:信号灯的值可以取任意非负值

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值