为了完成本周操作系统的作业,同时也学习一下这块的相关知识,所以写个博客记录下。
进程与线程
进程是操作系统中最核心的概念,它是内存中正在运行的程序的一个抽象,我们打开任务管理器:
这里运行的程序都是进程,一个进程就是一个正在执行程序的实例(它有输入、输出、程序算法以及状态),我们知道,对于一个应用来说,它可能同时会做很多事,比如在运行一个游戏时,会有键盘鼠标的信息处理以及画面的渲染等等,而线程之间的切换开销是比较大的(需要内核操作),所以,这就需要引入"线程"的概念了,线程是进程中的一个执行单位,一个进程可以含有多个线程,每个线程执行不同的任务,在同一个进程中的各个线程,都可以共享该进程所拥有的资源,所以,线程间的通信不需要调动内核,那么线程切换的开销是很小的,线程之间的通信也是很高效的。
我们可以通过任务管理器查看每个进程的线程,可以看出每个进程下面都有多个线程:
任务管理器
简单介绍了进程与线程,再来看看并发与并行:
并发与并行
- 1.并发性:指两个或多个事件在同一时间段内间隔发生。
- 2.并行性:指两个或多个事件在同一时刻发生。
现代的计算机已经将多个CPU(多核)集成到一个芯片上,但是对于每个CPU来说,一次也只能运行一个程序,所以对于一个CPU来说,从微观上来说,每个进程/线程的执行都是有先后顺序的,但是由于CPU会在这些进程/线程之间来回快速切换,宏观上看,所有的进程/线程都执行了,所以这是一种伪并行(实则是并发),要实现真正的并行,需要硬件的支持,即多个处理器,在同一时间,不同的处理起执行不同的进程/线程。
windows实现间进程通信
在网上查阅了相关资料,得知实现进程间通信的方式有很多,比如共享内存,匿名管道与命名管道,消息队列等(代码量都挺大的,而且涵盖很多目前没有学过的东西),所以我选择了一种比较好理解的方式来实现进程间的通信-共享内存
共享内存:是由一个进程创建的可以被其他进程访问的内存,进程可以直接读写内存,所以是一种高效的IPC方式
参考博客:点我跳转https://blog.51cto.com/liuker/1654814
我们需要一个服务端来创建共享内存,然后客户端进程从共享内存中读取数据,从而实现进程间通信。
服务端:
#include<cstdio>
#include<cstdlib>
#include <iostream>
#include<Windows.h>
#define FileMapping_NAME "Xidian"
#define FILESIZE 4096
LPVOID lpdata = NULL;//指针标识首地址
using namespace std;
int main()
{
if (lpdata != NULL){
cerr<<"Shared memory already exit!"<<endl;
}
//创建一个有名字标识的共享内存。
HANDLE hmap =CreateFileMappingA(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE | SEC_COMMIT,
0,
FILESIZE,
FileMapping_NAME);
if (hmap == NULL) //如果句柄指向NULL,表示创建失败
{
cerr<<"Create shared memory failed"<<endl;
}
else{
//映射文件到指针
lpdata = MapViewOfFile(hmap,FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
if (lpdata == NULL) //映射失败
{
cerr<<"Mapping failed!"<<endl;
}
else
{
char s[] = "Hello Xidian!";
memcpy(lpdata, s, sizeof s); //向这个内存中写入数据
}
}
system("pause");
UnmapViewOfFile(lpdata);//解除映射
CloseHandle(hmap);
system("pause");
return 0;
}
客户端:
#include <cstdio>
#include <cstdlib>
#include <Windows.h>
#include <iostream>
#define FileMapping_NAME "Xidian"
LPVOID lpdata = NULL;
using namespace std;
int main()
{
//打开一个指定的文件映射对象,获得共享内存对象的句柄
HANDLE hmapfile =OpenFileMappingA(FILE_MAP_READ, FALSE, FileMapping_NAME);
if (hmapfile == NULL){
cerr<<"Open mapfile failed"<<endl;//打开文件映射对象失败
}
else
{
//将一个文件映射对象映射到当前应用程序的地址空间。
LPVOID lpbase = MapViewOfFile(hmapfile,FILE_MAP_READ, 0, 0, 0);
if (lpbase == NULL)
{
cerr<<"Mapping failed!"<<endl;
}
else
{
char *p = (char *)lpbase;
cout<<p<<endl;
}
UnmapViewOfFile(lpbase);//解除映射
CloseHandle(hmapfile);//一个指定的文件映射对象
system("pause");
}
return 0;
}
流程:
首先,在服务端即第一个代码中,我们创建一个共享内存,用hmap保存返回的句柄(一个标识符,表示对象或者项目,在windows下用来表示被应用程序所建立或使用的对象的唯一整数),如果共享内存创建成功,将其映射到当前进程的地址空间,这样在服务器进程中我们就可以向内存中写入数据,比如,我们写了一个"Hello Xidian!"的字符串,接下来在客户端中即第二个代码,先打开我们创建好的文件映射对象,再用一个LPVOID(没有类型的指针,通常作为"中间变量")将文件映射对象映射到当前应用程序的地址空间,从这个地址空间中读取数据,观察是否是我们在服务端写的"Hello Xidian!",下面演示一下:
1.Clion中创建服务端:
Clion中创建服务端
2.Codeblocks中运行客户端:
Codeblocks中运行客户端
3.结果:
结果
4.关闭服务端的程序
结果
这样就实现了两个不同进程之间的通信。
网友评论