【C++】linux 下进程同步例子;实现共享内存、unix 域套接字;

本文详细探讨了进程间数据共享的不同途径,如管道、消息队列、共享内存和Unix域套接字,并着重比较了它们的易用性、效率和应用场景。通过实例展示了共享内存的 shmget/shmat/shmdt 和 Unix 套接字的创建与通信过程,适合操作系统和网络通信初学者学习。
摘要由CSDN通过智能技术生成

一、进程同步

1、比较

  • 进程间数据共享: 管道,消息队列,共享内存,unix 域套接字

对比:

  1. 易用性:消息队列 > unix 域套接字 > 管道 > 共享内存(配合信号量使用)
  2. 效率:共享内存 > unix 域套接字 > 管道 > 消息队列
  3. 常用:共享内存,unix 域套接字
  • 异步通讯:信号

  • 同步和互斥: 信号量

2、共享内存实现

  • 进程空间是通过页表,通过段页式存储管理,与实际物理内存建立的映射;
  • 所以进程间也是公用物理内存的;
  • 操作系统的进程管理,使得进程间内存空间独立;进程默认是不能访问进程空间之外的内存空间的;

共享内存:

  • 共享内存,允许不相关的进程访问同一片物理内存;
  • 共享内存是两个进程之间共享和传递数据最快的方式;
  • 共享内存未提供同步机制,需要借助其他机制管理访问;

使用共享内存:

  1. 申请共享内存 : shmget((key_t)1111,sizeof(struct ShmEntry),0666|IPC_CREAT);
  2. 连接到进程空间 : (ShmEntry*)shmat(shmid,0,0);连接到
  3. 使用共享内存
  4. 脱离进程空间&& 删除 : shmdt(entry); && shmctl(shmid,IPC_RMID,0);
#ifndef __COMMON_H_
#define __COMMON_H_

#define TEXT_LEN 2048

struct ShmEntry{
	bool can_read;
	char msg[2048];
};
  • server
#include "common.h"

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

#include <iostream>
int main()
{
	struct ShmEntry *entry;
	int shmid = shmget((key_t)1111,sizeof(struct ShmEntry),0666|IPC_CREAT);
	if(shmid ==-1)
	{
		std::cout<<"creat error!"<<std::endl;
		return -1;
	}
	std::cout<<"yes! "<<std::endl;
	entry = (ShmEntry*)shmat(shmid,0,0);
	entry->can_read = 0;
	while(true){
		if(entry->can_read == 1)
		{
			std::cout<<"msg : "<<entry->msg<<std::endl;
			entry->can_read = 0;
		}
		else
		{
			std::cout<<" sleep 1 second"<<std::endl;
			sleep(1);
		}
	}
	shmdt(entry);
	
	shmctl(shmid,IPC_RMID,0);
return 0;
}

  • client
#include "common.h"

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

#include <iostream>
int main()
{
	struct ShmEntry *entry;
	int shmid = shmget((key_t)1111,sizeof(struct ShmEntry),0666|IPC_CREAT);
	if(shmid ==-1)
	{
		std::cout<<"creat error!"<<std::endl;
		return -1;
	}
	std::cout<<"yes! "<<std::endl;
	entry = (ShmEntry*)shmat(shmid,0,0);
	entry->can_read = 0;
	char buffer[TEXT_LEN];
	while(true){
		if(entry->can_read == 0)
		{
			std::cout<<"input message: "<<std::endl;
			fgets(buffer,TEXT_LEN,stdin);
			strncpy(entry->msg,buffer,TEXT_LEN);
			
	
			entry->can_read = 1;
		}
	}

	shmdt(entry);
	
	shmctl(shmid,IPC_RMID,0);
return 0;
}
g++ server .cpp common.h -o server -g -lpthread
g++ client.cpp common.h -o client -g -lpthread
  • 实现
    在这里插入图片描述

3、Unix 域套接字实现

  • 套接字本是网络通信;
  • Unix系统提供的域套接字提供了网络套接字类似功能;
  • 他提供了单机、简单、可靠的进程通信同步服务;
  • 只能单机使用,不能跨机器使用;跨机器需要网络套接字;
  • 相比共享内存,提供的是可靠的信息传递,不需要维护同步信息;
  • Nginx 、 uWSGI 、 都会使用到;

server使用:

  1. 创建套接字
  2. 绑定套接字
  3. 监听套接字
  4. 接收&处理信息

client使用:

  1. 创建套接字
  2. 连接套接字
  3. 发送信息
  • server.cpp
#include <sys/types.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <netinet/in.h>
#include <iostream>

#define SOCKET_PATH "./domainsocket"
#define MSG_SIZE 2048
using namespace std;
int main()
{
	int socket_fd, accept_fd;
	int ret = 0;
	socklen_t addr_len;
	char msg[MSG_SIZE];
	struct sockaddr_un server_addr;
	//1
	socket_fd = socket(PF_UNIX,SOCK_STREAM,0);
	if (-1 == socket_fd)
	{
		cout << "socket create failed" << endl;
		return -1;
	}

	remove(SOCKET_PATH);

	bzero(&server_addr, sizeof(server_addr));
	server_addr.sun_family = PF_UNIX;
	strcpy(server_addr.sun_path, SOCKET_PATH);

	cout << "binding " << endl;
	//2
	ret = bind(socket_fd, (sockaddr*)&server_addr, sizeof(server_addr));
	if (0 > ret)
	{
		cout << "bind socket failed" << endl;
		return -1;
	}
	//3
	cout << "listening " << endl;
	ret = listen(socket_fd, 10);
	if (-1 == ret)
	{
		cout << "listen failed" << endl;
		return -1;
	}
	cout << "waiting new requests " << endl;
	accept_fd = accept(socket_fd, NULL, NULL);

	bzero(msg, MSG_SIZE);

	while (1)
	{
		//4
		recv(accept_fd, msg, MSG_SIZE, 0);
		cout << "received message : " << msg<<endl;
	}
	close(accept_fd);
	close(socket_fd);
	return 0;
}
  • client.cpp
#include <sys/types.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <netinet/in.h>
#include <iostream>

#define SOCKET_PATH "./domainsocket"
#define MSG_SIZE 2048
using namespace std;
int main()
{
	int socket_fd;
	int ret = 0;
	char msg[MSG_SIZE];
	struct sockaddr_un server_addr;
	//1
	socket_fd = socket(PF_UNIX,SOCK_STREAM,0);
	if (-1 == socket_fd)
	{
		cout << "socket create failed" << endl;
		return -1;
	}

	bzero(&server_addr, sizeof(server_addr));
	server_addr.sun_family = PF_UNIX;
	strcpy(server_addr.sun_path, SOCKET_PATH);

	cout << "connecting " << endl;
	//2
	ret = connect(socket_fd, (sockaddr*)&server_addr, sizeof(server_addr));
	if (-1 == ret)
	{
		cout << "bind socket failed" << endl;
		return -1;
	}

	while (1)
	{
		cout << "Input message >>> ";
		fgets(msg, MSG_SIZE, stdin);
		//3
		ret = send(socket_fd, msg, MSG_SIZE,0);
	}

	close(socket_fd);
	return 0;
}
g++ server.cpp -o server -g -lpthread
g++ client.cpp -o client -g -lpthread

实现:
在这里插入图片描述

参考

【学习笔记】【操作系统】

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值