每一个进程可能会有一个或多个线程,进程的线程共享进程资源,线程之间需要通信,或者线程需要同步一些关于进程资源的状态,这时需要线程之间进行信息的同步。
同样对于进程,一个操作系统里面可能有一个或者多个进程,进程共享计算机资源。包括内存,磁盘等。生产者消费者模型,哲学家就餐问题都属于进程同步的原因。
操作系统如何进行进程管理?
每一个进程都有进程空间,并且他们的进程空间通过段页式存储管理与实际的物理内存建立起映射。进程之间他们彼此的进程空间是互不干扰,相互独立的。因此,在某种程度上,多进程是共同使用物理内存的。但是由于操作系统的进程管理,进程间的内存空间是独立的,同时也保证了每一个进程独立运行的安全性。进程默认无法访问进程空间之外的内存空间。
共享内存
操作系统提供的重要的进程同步方法。
图片来源:慕课网《编程必备基础》
什么是共享内存
使用共享内存,不同的进程可以通过页表来映射到同一片内存里面。这一片共享内存可以被进程1读或者写,也可以被进程2读或者写。通过共享内存,进程1与进程2建立了联系。
共享内存允许不相关的进程访问同一片物理内存。
实现的原理是把这一片相同的物理内存分别映射到不同进程的页表里。使不同的进程可以通过页表访问。
共享内存是两个进程之间共享和传递数据最快的方式
。在后台,很多高性能的服务都是通过共享内存来实现进程间的通信。
共享内存没有提供同步机制
,因此需要借助其他机制管理多个进程间访问以避免并发访问带来的问题。
共享内存的方法
- 申请共享内存
shmget
- 把共享内存连接到进程空间
shmat
- 使用共享内存
- 脱离
shmdt
进程空间并且删除shmctl
模拟服务端和客户端使用共享内存
客户端与服务端通过借助结构体来管理内存
common.h
#ifndef __COMMON_H__
#define __COMMON_H__
#define TEXT_LEN 2048 // 定义字符串最大长度
// 共享内存的数据结构
struct ShmEntry{
// 是否可以读取共享内存,用于进程间同步
bool can_read;
// 共享内存信息
char msg[2048];
};
#endif
server.cpp
#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;
// 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);
// 设置为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;
}
client.cpp
#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;
// 1. 申请共享内存 返回共享内存id
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;
}