windows进程通信

Windows下实现进程间通信

2020-03-11  本文已影响0人  _NewMoon

为了完成本周操作系统的作业,同时也学习一下这块的相关知识,所以写个博客记录下。

进程与线程

进程是操作系统中最核心的概念,它是内存中正在运行的程序的一个抽象,我们打开任务管理器:

任务管理器
这里运行的程序都是进程,一个进程就是一个正在执行程序的实例(它有输入、输出、程序算法以及状态),我们知道,对于一个应用来说,它可能同时会做很多事,比如在运行一个游戏时,会有键盘鼠标的信息处理以及画面的渲染等等,而线程之间的切换开销是比较大的(需要内核操作),所以,这就需要引入"线程"的概念了,线程是进程中的一个执行单位,一个进程可以含有多个线程,每个线程执行不同的任务在同一个进程中的各个线程,都可以共享该进程所拥有的资源,所以,线程间的通信不需要调动内核,那么线程切换的开销是很小的,线程之间的通信也是很高效的。
我们可以通过任务管理器查看每个进程的线程,可以看出每个进程下面都有多个线程:
任务管理器

简单介绍了进程与线程,再来看看并发与并行:

并发与并行

现代的计算机已经将多个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.关闭服务端的程序


结果

这样就实现了两个不同进程之间的通信。

上一篇 下一篇

猜你喜欢

热点阅读