进程同步
使用fork系统调用创建进程
- fork系统调用是用于创建进程的
- fork创建的进程初始化状态与父进程一样
- 系统会为fork的进程分配新的资源
- fork系统调用无参数
- fork会返回两次,分别返回子进程id和0
- 返回子进程id的是父进程,返回0的是子进程
#include
#include
#include
#include
using namespace std;
int main()
{
// 进程id
pid_t pid;
int num = 888;
pid = fork();
if(pid == 0){
cout << "这是一个子进程." << endl;
cout << "num in son process: " << num << endl;
while(true){
num += 1;
cout << "num in son process: " << num << endl;
sleep(1);
}
} else if(pid > 0){
cout << "这是一个父进程." << endl;
cout << "子进程id: " << pid << endl;
cout << "num in father process: " << num << endl;
while(true){
num -= 1;
cout << "num in father process: " << num << endl;
sleep(1);
}
} else if (pid < 0){
cout << "创建进程失败." << endl;
}
return 0;
}
共享内存
进程默认是不能访问进程空间之外的内存空间的,但是在分配进程空间时可以让多个进程同时指向同一块内存空间
共享内存是两个进程之间共享和传递数据最快的方式,但是共享内存也有其缺点,它未提供同步机制,需要借助其它机制管理访问
步奏
- 申请共享内存
- 连接到进程空间
- 使用共享内存
- 脱离进程空间 & 删除
common.h
#ifndef __COMMON_H__
#define __COMMON_H__
#define TEXT_LEN 2048
// 共享内存的数据结构
struct ShmEntry{
// 是否可以读取共享内存,用于进程间同步
bool can_read;
// 共享内存信息
char msg[2048];
};
#endif
clinet.cpp
#include "common.h"
#include
#include
#include
#include
#include
#include
int main()
{
struct ShmEntry *entry;
// 1. 申请共享内存
int shmid = shmget((key_t)1111, sizeof(struct ShmEntry), 0666|IPC_CREAT);
if (shmid == -1){
std::cout << "Create share memory error!" << std::endl;
return -1;
}
// 2. 连接到当前进程空间/使用共享内存
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>>> ";
fgets(buffer, TEXT_LEN, stdin);
strncpy(entry->msg, buffer, TEXT_LEN);
std::cout << "Send message: " << entry->msg << std::endl;
entry->can_read = 1;
}
}
// 3. 脱离进程空间
shmdt(entry);
// 4. 删除共享内存
shmctl(shmid, IPC_RMID, 0);
return 0;
}
server.cpp
#include "common.h"
#include
#include
#include
#include
#include
#include
int main()
{
// 共享内存的结构体
struct ShmEntry *entry;
// 1. 申请共享内存
int shmid = shmget((key_t)1111, sizeof(struct ShmEntry), 0666|IPC_CREAT);
if (shmid == -1){
std::cout << "Create share memory error!" << std::endl;
return -1;
}
// 2. 连接到当前进程空间/使用共享内存
entry = (ShmEntry*)shmat(shmid, 0, 0);
entry->can_read = 0;
while (true){
if (entry->can_read == 1){
std::cout << "Received message: " << entry->msg << std::endl;
entry->can_read = 0;
}else{
std::cout << "Entry can not read. Sleep 1s." << std::endl;
sleep(1);
}
}
// 3. 脱离进程空间
shmdt(entry);
// 4. 删除共享内存
shmctl(shmid, IPC_RMID, 0);
return 0;
}
Unix域套接字
- 域套接字是一种高级的进程间通信的方法
- Unix域套接字可以用于同一机器进程间通信
- 套接字(socket)原始网络通信中使用的术语
- Unix系统提供的域套接字提供了网络套接字类似的功能
Server
创建套接字 -- 绑定套接字 -- 监听套接字 -- 接收处理信息
Client
创建套接字 -- 连接套接字 -- 发送信息
Server.cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// 域套接字
#define SOCKET_PATH "./domainsocket"
#define MSG_SIZE 2048
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){
std::cout << "Socket create failed!" << std::endl;
return -1;
}
// 移除已有域套接字路径
remove(SOCKET_PATH);
// 内存区域置0
bzero(&server_addr,sizeof(server_addr));
server_addr.sun_family = PF_UNIX;
strcpy(server_addr.sun_path, SOCKET_PATH);
// 2. 绑定域套接字
std::cout << "Binding socket..." << std::endl;
ret = bind(socket_fd,(sockaddr *)&server_addr,sizeof(server_addr));
if(0 > ret){
std::cout << "Bind socket failed." << std::endl;
return -1;
}
// 3. 监听套接字
std::cout << "Listening socket..." << std::endl;
ret = listen(socket_fd, 10);
if(-1 == ret){
std::cout << "Listen failed" << std::endl;
return -1;
}
std::cout << "Waiting for new requests." << std::endl;
accept_fd = accept(socket_fd, NULL, NULL);
bzero(msg,MSG_SIZE);
while(true){
// 4. 接收&处理信息
recv(accept_fd, msg, MSG_SIZE, 0);
std::cout << "Received message from remote: " << msg <
client.cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SOCKET_PATH "./domainsocket"
#define MSG_SIZE 2048
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){
std::cout << "Socket create failed!" << std::endl;
return -1;
}
// 内存区域置0
bzero(&server_addr,sizeof(server_addr));
server_addr.sun_family = PF_UNIX;
strcpy(server_addr.sun_path, SOCKET_PATH);
// 2. 连接域套接字
ret = connect(socket_fd, (sockaddr *)&server_addr, sizeof(server_addr));
if(-1 == ret){
std::cout << "Connect socket failed" << std::endl;
return -1;
}
while(true){
std::cout << "Input message>>> ";
fgets(msg, MSG_SIZE, stdin);
// 3. 发送信息
ret = send(socket_fd, msg, MSG_SIZE, 0);
}
close(socket_fd);
return 0;
}