进程可以理解为一个独立的程序和其支配的内存空间,是程序运行的实体。进程拥有独立的内存空间,在两个进程间实现数据共享相对线程要困难一些。在这系列文章中,对不同的进程间数据共享方式进行说明,并通过C++实例进行实现讲解。
搜索一下网上进程间通信方式,比较夸张的是说有“十一”种方法,方法虽多,但是基本原理都是相通的,一个东西不同包装而已。其实掌握主要方法,既可以应对日常的工作。本系列文章从常用方法说起,争取覆盖所有见得到的方法。
管道通信的方式,是通过建立管道文件,实现进程间的信息传输通道。
管道是常用的进程间通信方式,管道主要分为匿名管道和命名管道两种。
这里首先讲解匿名管道,余下的在后续文章中介绍。(这里插一句, “匿”的拼音为nin,写到这里要感慨一下自己的语文,学的还是有瑕疵。)
管道信息传输遵循“先入先出”(FIFO)原则,即先写入管道的信息,会被首先读取出来。
匿名管道(“Anonymous Pipe”)是管道中的一种,该类管道在使用过程中,有比较多的限制。匿名管道只能用于父子进程间的通信,这里我们定义父进程为程序的第一次入口,子进程是在父进程中,通过程序产生的进程,二者拥有了天然的亲缘关系。这种亲缘关系使得通信参数的传递更加便捷,可通过“标准读句柄”和“标准写句柄”在进程中获得管道文件的标识,从而实现通信。
结合例子进行讲解,例程如下。由于子进程必须由父进程创建,为了简化程序,这里将父进程和子进程写于同一主函数中,通过参数决定父子进程代码的不同。
父进程无输入参数,父进程首先创建管道,匿名管道传输中的管道必须由父进程创建,创建管道后启动子进程,在子进程的命令行中添加参数,实现进程的功能控制。在创建进程后,向管道写入数据,程序暂停,等待子进程读取。
子进程创建后,通过标准输入句柄获取管道文件,并从中读取父进程写入的信息,实现匿名管道通信。
注:此例为Windows平台下编程实例,应用windows平台封装的管道API实现通信。
文章中示例代码的完整工程文件可在http://download.csdn.net/detail/ezhchai/9895267中下载。
#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
if (argc > 1)
{
/* * * 子进程 * * */
cout << "Child Process" << endl;
/* * 接收管道数据,并显示 * */
CHAR szBuffer[16]{ 0 };
ReadFile(GetStdHandle(STD_INPUT_HANDLE), szBuffer, sizeof(szBuffer), nullptr, nullptr);
cout << szBuffer << endl;
}
else
{
/* * * 父进程 * * */
cout << "Parent Process" << endl;
HANDLE hPipeW = NULL, hPipeR = NULL; //读管道句柄和写管道句柄
//安全性结构
SECURITY_ATTRIBUTES sa{ 0 };
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;//填充安全性结构使句柄被继承
// 创建匿名管道
if (!CreatePipe(&hPipeR, &hPipeW, &sa, 0))
{
cout << "Create pipe failed! Processs return!" << endl;
return 1;
}
// 进程信息结构体
PROCESS_INFORMATION pi{ 0 };
// 进程启动窗体信息结构体
STARTUPINFOA si{ 0 };
si.cb = sizeof(si);
si.hStdInput = hPipeR;
si.dwFlags = STARTF_USESTDHANDLES;
// 为子进程命令行添加参数
char param[1024];
sprintf_s(param, "%s %s", argv[0], "test");
// 创建子进程
if (!CreateProcessA(nullptr, param, nullptr, nullptr, TRUE, CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi))
{
CloseHandle(hPipeR);
CloseHandle(hPipeW);
cout << "Create child process failed! Process return!" << endl;
return 2;
}
// 写管道数据
WriteFile(hPipeW, "ezhchai", 7, nullptr, nullptr);
}
system("pause");
return 0;
}