C++进阶(应用篇)—第2章 进程间的通信(补)

2.3.2匿名管道

//匿名管道

//father.cpp

#include <windows.h>

#include <iostream>

 

using namespace std;

#define BUF_SIZE 4096

 

#define CHILD_ADDR L"C:\\Users\\gyrt\\Documents\\Visual Studio 2008\\Projects\\unnamed_pipe2\\Debug\\child.exe"

 

//父进程到子进程的管道,父进程一端写入,子进程一端读出

HANDLE g_hFtoCStd_Wr,g_hFtoCStd_Rd;

//子进程到父进程的管道,子进程一端写入,父进程一端读出

HANDLE g_hCtoFStd_Wr,g_hCtoFStd_Rd;

 

int main(int argc,char ** argv)

{

//步骤1:创建匿名管道

SECURITY_ATTRIBUTES saAttr;

saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);

saAttr.bInheritHandle = TRUE;

saAttr.lpSecurityDescriptor = NULL;

 

//CreatePipe:参数是对管道读的HANDLE,参数是对管道写的HANDLE

if (!CreatePipe(&g_hFtoCStd_Rd,&g_hFtoCStd_Wr, &saAttr, 0))

{

cout << "Create Unnamed_Pipe Failed..." << endl;

return 1;

}

if (!CreatePipe(&g_hCtoFStd_Rd, &g_hCtoFStd_Wr, &saAttr, 0))

{

cout << "Create Unnamed_Pipe Failed..." << endl;

return 1;

}

 

//步骤2:设置父进程端的管道口不可继承

//设置句柄不可继承(子进程)

if (!SetHandleInformation(g_hFtoCStd_Wr, HANDLE_FLAG_INHERIT, 0))

{

cout << "hFtoCStdinWr is not inherited by child process." << endl;

return 1;

}

//设置句柄不可继承

if (!SetHandleInformation(g_hCtoFStd_Rd, HANDLE_FLAG_INHERIT, 0))

{

cout << "hCtoFStdoutRd is not inherited by child process." << endl;

return 1;

}

 

//步骤3:创建子进程

//TCHAR szCommandLINE[] = TEXT("child.exe");//TEXT("child")等价于L"child"

STARTUPINFO si;

ZeroMemory(&si, sizeof(STARTUPINFO));

si.cb = sizeof(STARTUPINFO);

si.hStdError = g_hCtoFStd_Wr;

si.hStdOutput = g_hCtoFStd_Wr; //将子进程的标准输出重定向到匿名管道的写段

si.hStdInput = g_hFtoCStd_Rd; //将子进程的标准输入重定向到匿名管道的读端

si.dwFlags |= STARTF_USESTDHANDLES;

PROCESS_INFORMATION pi; //pi 获取子进程的信息

ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

//CreateProcess方法1:通过路径来打开子进程

int ret = CreateProcess(CHILD_ADDR, NULL,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi);

//CreateProcess方法2:子进程的exe文件必须放在父进程中,然后打开

//int ret = CreateProcess(NULL, szCommandLINE,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi);

if (ret)

{

printf("child process created.\n");

//父进程不需要子进程的系统资源,因此将子进程句柄和子进程的线程句柄关闭

//当然某些程序可能会保留这些句柄来监视子进程状态

CloseHandle(pi.hProcess);

CloseHandle(pi.hThread);

}

 

//步骤4:读写匿名管道

//4.1:打开my.txt文件的句柄

HANDLE h_mytxt = CreateFile(

L"my.txt",

GENERIC_READ,

0,

NULL,

OPEN_EXISTING,

FILE_ATTRIBUTE_READONLY,

NULL);

 

//4.2:读取文件my.txt,输出到匿名管道g_hFtoCStd_Wr,即向子进程写数据

{

char szBuffer[BUF_SIZE] = { 0 };

DWORD wLen = 0;

DWORD rLen = 0;

int rRet = 0;

int wRet = 0;

 

for(;;)

{

//ReadFile读文件句柄:第一次读取结束后,第二次读取若文件内容未改动,则不再读取

//ReadFile读管道句柄:第一次读取结束后,清除管道缓冲区,因此第二次读取管道若无数据,一直等待

rRet = ReadFile(h_mytxt, szBuffer, BUF_SIZE, &rLen, NULL);

if(!rRet || rLen == 0)

break;

wRet = WriteFile(g_hFtoCStd_Wr, szBuffer, strlen(szBuffer) + 1, &wLen, NULL);

if(!wRet)

break;

}

}

 

//4.3:输出重定向到句柄hStdout

HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

 

//4.4:从子进程读取数据,再通过hStdout输出

{

char szBuffer[BUF_SIZE] = { 0 };

DWORD wLen = 0;

DWORD rLen = 0;

int rRet = 0;

int wRet = 0;

for(;;)

{

rRet = ReadFile(g_hCtoFStd_Rd, szBuffer, BUF_SIZE, &rLen, NULL);

if(!rRet || rLen == 0)

break;

else

cout << "Read Successed..." << endl;

wRet = WriteFile(hStdout, szBuffer, strlen(szBuffer) + 1, &wLen, NULL);

if(!wRet)

break;

else

cout <<"Write Successed..." << endl;

}

}

 

//步骤5:关闭句柄

CloseHandle(g_hFtoCStd_Wr);

CloseHandle(g_hFtoCStd_Rd);

CloseHandle(g_hCtoFStd_Wr);

CloseHandle(g_hCtoFStd_Rd);

CloseHandle(h_mytxt);

CloseHandle(hStdout);

return 0;

}

//匿名管道

//child.cpp

#include <windows.h>

#include <iostream>

 

using namespace std;

#define BUF_SIZE 4096

HANDLE h_Stdin,h_Stdout;

int main(int argc,char ** argv)

{

//步骤1:子进程输出输入重定向

h_Stdin = GetStdHandle(STD_INPUT_HANDLE);

h_Stdout = GetStdHandle(STD_OUTPUT_HANDLE);

 

if (h_Stdin == INVALID_HANDLE_VALUE

|| h_Stdout == INVALID_HANDLE_VALUE)

{

cout << "Get Std_Handle Failed..." << endl;

ExitProcess(1);

}

 

//相当于执行WriteFile(h_Stdout,...)

cout<<"*This is a message from the child process.*"<<endl;

_sleep(500);

cout<<"***This is a message from the child process.***"<<endl;

 

char szBuffer[BUF_SIZE] = { 0 };

DWORD wLen = 0;

DWORD rLen = 0;

int rRet = 0;

int wRet = 0;

 

//步骤2:读写匿名管道

for(;;)

{

rRet = ReadFile(h_Stdin, szBuffer, BUF_SIZE, &rLen, NULL);

if(!rRet || rLen == 0)

break;

wRet = WriteFile(h_Stdout, szBuffer, strlen(szBuffer) + 1, &wLen, NULL);

if(!wRet)

break;

}

 

//步骤3:关闭句柄

CloseHandle(h_Stdin);

CloseHandle(h_Stdout);

return 0;

}

运行结果:

child process created.

Read Successed...

*This is a message from the child process.*

 Write Successed...

Read Successed...

***This is a message from the child process.***

 Write Successed...

Read Successed...

hello world

hello C++

你好,中国! Write Successed...

父进程从my.txt中读取数据,然后输出到匿名管道,发送给子进程;子进程读取到数据后,再发送会父进程;父进程读取子进程中传来的数据,然后通过标准输出重定向的句柄来输出数据。

BOOL WINAPI CreatePipe(参数1,参数2,参数3,参数4):创建匿名管道,并得到读写管道。

参数1:对匿名管道读的句柄;

参数2:对匿名管道写的句柄;

参数3:指向SECURITY_ATTRIBUTES结构的指针,SECURITY_ATTRIBUTES是用来设置管道的访问权限。SECURITY_ATTRIBUTES成员bInheritHandle是设置句柄是否被子进程继承,若为ture则可以被继承;SECURITY_ATTRIBUTES成员lpSecurityDescriptor表示指向安全描述符(Security_Descriptor)的指针,若为NULL,则表示管道设置为默认安全属性。

参数4:管道缓冲区的大小,若设置0,则使用系统默认的缓冲区大小。

BOOL WINAPI SetHandleInformation(参数1,参数2,参数3):控制子进程获得对象句柄的继承权。

参数1:标识一个句柄;

参数2:若为HANDLE_FLAG_INHERIT表示创建的子进程可以获得对象句柄。

HANDLE GetStdHandle( DWORD nStdHandle ):用于从一个特定的标准设备(标准输入、标准输出或标准错误)中取得一个句柄。

BOOL CreateProcess

(

LPCTSTR lpApplicationName,

LPTSTR lpCommandLine,

LPSECURITY_ATTRIBUTES lpProcessAttributes,

LPSECURITY_ATTRIBUTES lpThreadAttributes,

BOOL bInheritHandles,

DWORD dwCreationFlags,

LPVOID lpEnvironment,

LPCTSTR lpCurrentDirectory,

LPSTARTUPINFO lpStartupInfo,

LPPROCESS_INFORMATION lpProcessInformation

)

函数作用:创建子进程。在宽字符版本中实际调用的是CreateProcessW,窄字符版本中调用的则是CreateProcessA。

参数1:lpApplicationName,指向可执行模块的字符串。这个字符串可以是可执行模块的绝对路径或相对路径。注:若设为NULL,则参数2必须要设置。

参数2:lpCommandLine,指定要运行的命令行。此命令行是子进程的可执行模块,并且需要放在父进程代码下。

参数3:lpProcessAttributes,指向SECURITY_ATTRIBUTES结构的指针,这里设为为NULL。

参数4:lpThreadAttributes,指向SECURITY_ATTRIBUTES结构的指针,这里设为为NULL。

参数5:bInheritHandles,指示子进程是否从父进程处继承句柄,这里设为TRUE。

参数6:dwCreationFlags,这里设为0。

参数7:lpEnvironment,指示子进程的环境块,若设为NULL,则使用父进程的环境。

参数8:lpCurrentDirectory,指定子进程的工作路径,若设为NULL,则子进程和父进程使用相同的驱动器和目录。

参数9:lpStartupInfo,指向StartupInfo结构的指针。StartupInfo结构体用于指定新进程的主窗口特性:设置了标准错误/输出/输入;dwFlags设置为STARTF_USESTDHANDLES表示使用hStdInput、hStdOutput和hStdError成员。

参数10:lpProcessInformation,指向PROCESS_INFORMATION结构的指针。PROCESS_INFORMATION结构体用于存放进程信息。

2.4信号量

//进程1

#include <iostream>

#include <windows.h>

#include <process.h>

using namespace std;

 

int g_var;

//步骤1:创建句柄

HANDLE H_Semaphore = NULL;

UINT WINAPI ThreadOne(LPVOID lpParameter)

{

 

printf("进程正在执行...\n");

//步骤3:释放信号量

ReleaseSemaphore(H_Semaphore, 1, NULL);

return 1;

}

 

 

int main(int argc, char **argv)

{

//步骤2:使用CreateSemaphore创建信号量

H_Semaphore = CreateSemaphore(NULL,0,1,L"pSemaphore");

if(H_Semaphore == NULL)

printf("创建失败\n");

 

unsigned int thread_id = 0;

 

HANDLE HOne =(HANDLE)_beginthreadex(NULL, 0, ThreadOne, NULL, 0, &thread_id);

 

WaitForSingleObject(HOne, INFINITE);

while(1)

{

 

}

 

CloseHandle(HOne);

//步骤4:使用CloseHandle关闭信号量句柄

CloseHandle(H_Semaphore);

 

return 0;

}

//进程2

#include <iostream>

#include <windows.h>

#include <process.h>

using namespace std;

 

int g_var;

//步骤1:创建句柄

HANDLE H_Semaphore2 = NULL;

UINT WINAPI ThreadOne(LPVOID lpParameter)

{

//步骤3:等待信号量释放

WaitForSingleObject(H_Semaphore2, INFINITE);

printf("获得信号量,进程开始执行\n...\n");

printf("进程执行结束!\n");

return 1;

}

 

int main(int argc, char **argv)

{

//步骤2:使用OpenSemaphore打开信号量

H_Semaphore2 = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE,L"pSemaphore");

if(H_Semaphore2 == NULL)

{

printf("打开信号量失败\n");

exit(1);

}

else

printf("打开信号量成功\n");

 

unsigned int thread_id = 0;

 

HANDLE HOne = (HANDLE)_beginthreadex(NULL, 0, ThreadOne, NULL, 0, &thread_id);

 

WaitForSingleObject(HOne, INFINITE);

 

CloseHandle(HOne);

//步骤4:使用CloseHandle关闭信号量句柄

CloseHandle(H_Semaphore2);

 

return 0;

}

进程1运行结果:

进程1正在执行...

进程2运行结果:

打开信号量成功

获得信号量,进程2开始执行

...

进程2执行结束!

必须进程1开始执行后,再运行进程2。

OpenSemaphore(参数1,参数2,参数3):打开创建的信号量。

参数1:若是SEMAPHORE_ALL_ACCESS,表示对信号量的完全访问。

参数2:信号量句柄是否被子进程继承。

参数3:信号量的名称,类型为宽字符指针。

猜你喜欢

转载自blog.csdn.net/Bing_bing_bing_/article/details/83005888