目录
管道是一个有两端的对象。一个进程向管道写入信息,而另外一个进程从管道读取信息。进程可以从这个对象的一个端口写数据,从另一个端口读数据。创建管道的进程称为管道服务器(Pipe Server),而连接到这个管道的进程称为管道客户端(Pipe Client)。
在 Windows 系统中,存在两种类型的管道: “匿名管道”(Anonymous pipes)和“命名管道”(Named pipes)。匿名管道是基于字符和半双工的(即单向);命名管道是面向消息和全双工的,同时还允许网络通信,用于创建客户端/服务器系统。
匿名管道:单向通信,只能本地使用。由于匿名管道单向通信,且只能在本地使用的特性,一般用于程序输入输出的重定向,如一些后门程序获取 cmd 内容等等。
命名管道是一个具有名称,可在同一台计算机的不同进程之间或在跨越一个网络的不同计算机的不同进程之间,支持可靠的、单向或双向的数据通信管道。命名管道的所有实例拥有相同的名称,但是每个实例都有其自己的缓冲区和句柄,用来为不同客户端提供独立的管道。任何进程都可以访问命名管道,并接受安全权限的检查,通过命名管道使相关的或不相关的进程之间的通讯变得异常简单。
win c++标准函数中,已提供了CreateNamedPipe、ConnectNamedPipe、WriteFile、ReadFile、CloseHandle等创建、连接、使用、关闭的管道操作函数,本测试中,将建立进可能多的线程,对通一命名管道进行大量、快速的读写操作。
本次测试将创建一个管道,并创建ipc服务端接收数据和ipc客户端发送数据,同时有300百个线程对管道进行数据写入及读取操作,测试完成10万次数据写入及读取操作,看看是否其管道通信效率如何。
本文采用vs2010+cmake完成编译测试,测试代码目录结构如下:
- ipc_test
- bin
- build
- ipc
- ipcclient.h
- ipcclient.cpp
- ipcserver.h
- ipcserver.cpp
- src
- main.cpp
- CMakeLists.txt
ipcclient.h
- #ifndef _IPC_CLIENT_H_
- #define _IPC_CLIENT_H_
-
- #include
-
- class IPCClient
- {
- public:
- IPCClient(int n);
- ~IPCClient();
-
- int WriteInfo(char *, DWORD , DWORD* );
- int ReadInfo(char *, DWORD , DWORD* );
- private:
- bool Connect();
- private:
- int _nID;
- HANDLE _hPipe;
- bool _bConnected;
- };
-
- #endif // _IPC_CLIENT_H_
ipcclient.cpp实现管道打开连接、数据写入操作,管道名称和服务端保持一致,例如"\\\\.\\pipe\\pyfree"。
- #include "ipcclient.h"
-
- #include
- #include
-
- IPCClient::IPCClient(int n)
- : _nID(n)
- , _bConnected(false)
- , _hPipe(INVALID_HANDLE_VALUE)
- {
- Connect();
- }
-
- IPCClient::~IPCClient()
- {
- if(_hPipe!=INVALID_HANDLE_VALUE){
- CloseHandle(_hPipe);
- _hPipe = INVALID_HANDLE_VALUE;
- }
- }
-
- bool IPCClient::Connect()
- {
- if(_bConnected)
- return _bConnected;
- _bConnected = false;
- std::string path = "\\\\.\\pipe\\pyfree";
- path += std::to_string(long long(_nID));
- if (!WaitNamedPipe(path.c_str(), NMPWAIT_USE_DEFAULT_WAIT/* NMPWAIT_WAIT_FOREVER*/) == FALSE)
- {
- _hPipe = CreateFile(path.c_str(),
- GENERIC_READ|GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL/*|FILE_FLAG_OVERLAPPED*/,
- NULL);
- if(INVALID_HANDLE_VALUE != _hPipe)
- _bConnected = true;
- }
- return _bConnected;
- }
-
-
- int IPCClient::ReadInfo(char * buf, DWORD dwMaxLen, DWORD* pdwLen)
- {
- int nRet = 0;
- if(!Connect())
- return -1;
- if(!ReadFile(_hPipe,buf,dwMaxLen,pdwLen,NULL))
- {
- DWORD dwError = GetLastError();
- if(ERROR_IO_PENDING != dwError)
- {
- CloseHandle(_hPipe);
- _hPipe = INVALID_HANDLE_VALUE;
- _bConnected = false;
- nRet = 0 - dwError;
- }
- }
- return nRet;
- }
- int IPCClient::WriteInfo(char * buf, DWORD nMaxLen, DWORD* pdwLen)
- {
- int nRet = 0;
- if(!Connect())
- return -1;
- if(!WriteFile(_hPipe,buf,nMaxLen,pdwLen,NULL))
- {
- DWORD dwError = GetLastError();
- if(ERROR_IO_PENDING != dwError)
- {
- CloseHandle(_hPipe);
- _bConnected = false;
- _hPipe = INVALID_HANDLE_VALUE;
- nRet = 0 - dwError;
- }
- }
- return nRet;
- }
ipcserver.h
- #ifndef _IPC_SERVER_H_
- #define _IPC_SERVER_H_
-
- #include
-
- //const DWORD BUFSIZE = 1024*64;
- const DWORD BUFSIZE = 512;
- const DWORD PIPE_TIMEOUT = 3000;
-
- class IPCServer
- {
- public:
- IPCServer(int n);
- ~IPCServer();
- int ReadInfo(char *, DWORD , DWORD*);
- int WriteInfo(char *, DWORD , DWORD*);
- private:
- bool Connect();
- bool DisConnect();
- private:
- int _nID;
- HANDLE _hPipe;
- bool _bConnected;
- };
-
- #endif // _IPC_SERVER_H_
ipcserver.cpp实现管道创建、等待连接、数据读取等操作,管道名称和ipcclient保持一致,例如"\\\\.\\pipe\\pyfree"。
- #include "ipcserver.h"
-
- #include
- #include
- #include
-
- IPCServer::IPCServer(int n)
- : _nID(n)
- , _bConnected(false)
- , _hPipe(INVALID_HANDLE_VALUE)
- {
- Connect();
- }
-
- IPCServer::~IPCServer()
- {
- CloseHandle(_hPipe);
- }
-
- bool IPCServer::Connect()
- {
- if(_bConnected)
- return _bConnected;
- if(_hPipe == INVALID_HANDLE_VALUE)
- {
- std::string path = "\\\\.\\pipe\\pyfree";
- path += std::to_string(long long(_nID));
- _hPipe = CreateNamedPipe(path.c_str(),
- PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
- 1,
- BUFSIZE,
- BUFSIZE,
- PIPE_TIMEOUT,
- NULL);
- }
- if (_hPipe == INVALID_HANDLE_VALUE)
- {
- //std::cout << "CreatePipe Error" << std::endl;
- return _bConnected;
- }
- HANDLE hEvent;
- hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
- if (!hEvent)
- {
- CloseHandle(hEvent);
- //std::cout << "CreateEvent Error" << std::endl;
- return _bConnected;
- }
- OVERLAPPED olp;
- ZeroMemory(&olp,sizeof(OVERLAPPED));
- olp.hEvent=hEvent;
- if(!ConnectNamedPipe(_hPipe, &olp))
- {
- if(ERROR_IO_PENDING != GetLastError())//waitfor client link。
- {
- CloseHandle(_hPipe);
- CloseHandle(hEvent);
- _hPipe = INVALID_HANDLE_VALUE;
- //std::cout << "ConnectPipe Error" << std::endl;
- return _bConnected;
- }
- }
- DWORD waitforEvent = WaitForSingleObject(hEvent,INFINITE);
- if(WAIT_FAILED==waitforEvent||WAIT_TIMEOUT==waitforEvent)
- {
- CloseHandle(hEvent);
- CloseHandle(_hPipe);
- _hPipe = INVALID_HANDLE_VALUE;
- //std::cout << "ConnectPipe1 Error" << std::endl;
- return _bConnected;
- }
- CloseHandle(hEvent);
- _bConnected = true;
- return _bConnected;
- }
-
-
- bool IPCServer::DisConnect()
- {
- if(_bConnected)
- {
- if(DisconnectNamedPipe(_hPipe))
- {
-
- }
- CloseHandle(_hPipe);
- }
- _bConnected = false;
- _hPipe = INVALID_HANDLE_VALUE;
- return true;
- }
-
-
-
- int IPCServer::ReadInfo(char *wbuf, DWORD dwMaxLen, DWORD* pdwLen)
- {
- if(!Connect())
- return -1;
- int nRet = 0;
- if(!ReadFile(_hPipe,wbuf,dwMaxLen,pdwLen,NULL))
- {
- DWORD dwError = GetLastError();
- if(ERROR_IO_PENDING != dwError)
- {
- DisConnect();
- nRet = 0 - dwError;
- }
- }
- return nRet;
- }
-
- int IPCServer::WriteInfo(char *buf, DWORD dwMaxLen, DWORD* pdwLen)
- {
- int nRet = 0;
- if(!Connect())
- return -1;
- if(!WriteFile(_hPipe,buf,dwMaxLen,pdwLen,NULL))
- {
- DWORD dwError = GetLastError();
- if(ERROR_IO_PENDING != dwError)
- {
- DisConnect();
- nRet = 0 - dwError;
- }
- }
- return nRet;
- }
main.cpp实现创建线程,调用管道客户端(ipcclient)、服务端(ipcserver)实现数据的逻辑发送和接收,可以通过调整线程数量、发送数据宽度等调节进行压力测试。
- // main.cpp
- #include
- #include
- #include
- #include
-
- #include "ipcclient.h"
- #include "ipcserver.h"
-
- #define _TotalFrame 100000 //帧数量
- #define _TotalThread 300 //线程数
- //#define _strWhith 1024*64 //发送信息长度
- #define _strWhith 512 //发送信息长度
-
- int nErrorCnt[_TotalThread] = {0};
- int nCount[_TotalThread]={0};
- int nAllSendCount[_TotalThread] = {0};
- int nAllReciveCount[_TotalThread] = {0};
- int m_MaxMsec[_TotalThread][2] = {0};
- int nSendCount[_TotalThread] ={0};
-
- unsigned __stdcall Sender( void* parg )
- {
- int n = (int ) parg; //线程编号
- char buf[_strWhith] = {0}; //发送信息及初始化
- IPCClient h(n);
- int msec=0; //开始标记
- for(int i=0;i<_TotalFrame;)
- {
- nAllSendCount[n]++;
- int *p = (int *)buf;
- p[0] = n; //线程编号加入发送信息
- p[1] = i; //发送次数加入发送信息
-
- buf[_strWhith-1] = 'N';
- DWORD wlen=0; //实际发送长度标记
- DWORD dwBegin = GetTickCount();
- int ret = h.WriteInfo(buf, _strWhith/4, &wlen); //发送四分之一长度数据
- msec = GetTickCount() - dwBegin;
-
- if(msec > m_MaxMsec[n][0]){
- m_MaxMsec[n][0] = msec;
- m_MaxMsec[n][1] = ret;
- }
- if(3==ret){
- std::cout << "error: info too long!" << std::endl;
- }
- if( ret == 0&&_strWhith/4==wlen)
- {
- i++;
- nCount[n] = i;
- }
- ::Sleep(1);
- }
- return 1;
- }
- unsigned __stdcall Receiver( void* parg )
- {
- int n = (int ) parg; //线程编号
- char buf[_strWhith] = {0}; //接收信息及初始化
- IPCServer h(n);
- int msec = 0;
- int want = 0;
- for(int i=0;i<_TotalFrame;)
- {
- nAllReciveCount[n]++;
- int *p = (int *) buf;
- int nRet = 0;
- DWORD rlen = 0;
- DWORD dwBegin = GetTickCount();
- nRet = h.ReadInfo(buf, _strWhith,&rlen);
- msec = GetTickCount() - dwBegin;
- if(msec > m_MaxMsec[n][0]){
- m_MaxMsec[n][0] = msec;
- m_MaxMsec[n][1] = nRet;
- }
- //实际接收数据长度不是四分之一,说明缓存过多,对管道的数据读取效率到了极限
- if(nRet == 0&&_strWhith/4!=rlen){
- if(n<10)
- std::cout << "Thread " << n << " received " << rlen << " string , send order:" << p[1] << std::endl;
-
- int a=0;
- if(_strWhith/2==rlen)
- {
- a=2;
- }
- else if(3*_strWhith/4==rlen)
- {
- a=3;
- }
- else if(_strWhith==rlen)
- {
- a=4;
- }
- if(p[1] != want)
- {
- if(n<10)
- std::cout << "thread " << n << " want " << want << " , actual:" << p[1] << std::endl;
- nErrorCnt[n] = nErrorCnt[n] + 2;
- }
- nCount[n] = nCount[n] + a;
- want = p[1] + a;
- i=i+a;
- }
- //实际接收数据长度就是四分之一,即每次发送都能及时完全读取
- if(nRet == 0&&_strWhith/4==rlen)
- {
- if(p[1] != want)
- {
- if(n<1)
- std::cout << "Thread " << n << " want " << want << " , actual:" << p[1] << std::endl;
- nErrorCnt[n] ++;
- }
- nCount[n] ++;
- want = p[1] + 1;
- i++;
- }
- ::Sleep(1);
- }
- return 1;
- }
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- unsigned nThreadID[2][_TotalThread]; //两种线程句柄,一组用于发送、一组用于接收
- int bSender = 0;
- std::cout << "0: Receiver, 1: Sender" << std::endl;
- int ch = _getch(); //本次启动用于发送或接收选择
- if(ch == '1')
- {
- bSender = 1;
- }
-
- std::cout <<(bSender?"Start Sending":"Start Receiving") << std::endl;
- for(int i=0;i<_TotalThread;i++)
- {
- HANDLE hThread;
- if(bSender)
- hThread = (HANDLE)_beginthreadex(NULL, 0 , Sender, (void *)i, 0, nThreadID[0] + i);
- else
- hThread = (HANDLE)_beginthreadex(NULL, 0 , Receiver, (void *)i, 0, nThreadID[1] + i);
- if( 0 == hThread ){
- std::cout << "create thread : " <<(bSender?nThreadID[0][i]:nThreadID[1][i])<< " error! " << std::endl;
- }
- }
- bool bExit = false;
- for(;!bExit;)
- {
- ::Sleep(1);
- if(_kbhit())
- {
- int ch = _getch();
- switch(ch)
- {
- case 'q':
- bExit = true;
- break;
- case 'd':
- std::cout << " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ " << std::endl;
- for(int i=0;i<_TotalThread;i++){
- //if(m_MaxMsec[i][0]>20 || nErrorCnt[i])
- {
- std::cout << (bSender?"Sender ":"Reciever ")
- << i << /*" ,Max is:" << nMaxmsec <<*/" Error: "
- << nErrorCnt[i] << " Success : "<
- << (bSender?" STotal: ":" RTotal: ") << (bSender?nAllSendCount[i]:nAllReciveCount[i])
- << " maxTime: "<< m_MaxMsec[i][0]
- << " type: " << m_MaxMsec[i][1]
- << std::endl;
- }
- }
- break;
- }
- }
- }
- return 0;
- }
-
三、编译实现
CMakeLists.txt内容,本文给出Debug版本的。
- # CMake 最低版本号要求
- cmake_minimum_required(VERSION 2.8)
- # 项目信息
- project(ipc_test)
- #
- message(STATUS "windows compiling...")
- add_definitions(-D_PLATFORM_IS_WINDOWS_)
- #set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
- set(WIN_OS true)
- #
- set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
-
- # 指定源文件的目录,并将名称保存到变量
- SET(source_h
- #
- ${PROJECT_SOURCE_DIR}/ipc/ipcclient.h
- ${PROJECT_SOURCE_DIR}/ipc/ipcserver.h
- )
-
- SET(source_cpp
- #
- ${PROJECT_SOURCE_DIR}/ipc/ipcclient.cpp
- ${PROJECT_SOURCE_DIR}/ipc/ipcserver.cpp
- ${PROJECT_SOURCE_DIR}/src/main.cpp
- )
-
- #头文件目录
- include_directories(${PROJECT_SOURCE_DIR}/ipc)
-
- set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/bin)
- # 指定生成目标
- add_executable(ipc_testd ${source_h} ${source_cpp})
打开vs2010 command prompt命令工具
- cmake -G "Visual Studio 10 2010 Win64" ..
- msbuild ipc_test.sln /p:Platform="x64"
编译过程如下:
- D:\workForMy\workspace\ipc_test\build>cmake -G "Visual Studio 10 2010 Win64" ..
- -- The C compiler identification is MSVC 16.0.40219.1
- -- The CXX compiler identification is MSVC 16.0.40219.1
- -- Check for working C compiler: d:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin/x86_amd64/cl.exe
- -- Check for working C compiler: d:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin/x86_amd64/cl.exe -- works
- -- Detecting C compiler ABI info
- -- Detecting C compiler ABI info - done
- -- Check for working CXX compiler: d:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin/x86_amd64/cl.exe
- -- Check for working CXX compiler: d:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin/x86_amd64/cl.exe -- works
- -- Detecting CXX compiler ABI info
- -- Detecting CXX compiler ABI info - done
- -- Detecting CXX compile features
- -- Detecting CXX compile features - done
- -- windows compiling...
- -- Configuring done
- -- Generating done
- -- Build files have been written to: D:/workForMy/workspace/ipc_test/build
- D:\workForMy\workspace\ipc_test\build>msbuild ipc_test.sln /p:Platform="x64"
- Microsoft(R) 生成引擎版本 4.8.4084.0
- [Microsoft .NET Framework 版本 4.0.30319.42000]
- 版权所有 (C) Microsoft Corporation。保留所有权利。
-
- 在此解决方案中一次生成一个项目。若要启用并行生成,请添加“/m”开关。
- 生成启动时间为 2022/9/11 15:34:14。
- 节点 1 上的项目“D:\workForMy\workspace\ipc_test\build\ipc_test.sln”(默认目标)。
- ValidateSolutionConfiguration:
- 正在生成解决方案配置“Debug|x64”。
- ValidateProjects:
- 在解决方案配置“Debug|x64”中未选定生成项目“ALL_BUILD”。
- 项目“D:\workForMy\workspace\ipc_test\build\ipc_test.sln”(1)正在节点 1 上生成“D:\workForMy\workspace\ipc_test\build\ZERO_CHECK.vc
- xproj”(2) (默认目标)。
- PrepareForBuild:
- 正在创建目录“x64\Debug\ZERO_CHECK\”。
- InitializeBuildStatus:
- 正在创建“x64\Debug\ZERO_CHECK\ZERO_CHECK.unsuccessfulbuild”,因为已指定“AlwaysCreate”。
- CustomBuild:
- Checking Build System
- CMake does not need to re-run because D:/workForMy/workspace/ipc_test/build/CMakeFiles/generate.stamp is up-to-date.
- FinalizeBuildStatus:
- 正在删除文件“x64\Debug\ZERO_CHECK\ZERO_CHECK.unsuccessfulbuild”。
- 正在对“x64\Debug\ZERO_CHECK\ZERO_CHECK.lastbuildstate”执行 Touch 任务。
- 已完成生成项目“D:\workForMy\workspace\ipc_test\build\ZERO_CHECK.vcxproj”(默认目标)的操作。
-
- 项目“D:\workForMy\workspace\ipc_test\build\ipc_test.sln”(1)正在节点 1 上生成“D:\workForMy\workspace\ipc_test\build\ipc_testd.vcx
- proj.metaproj”(3) (默认目标)。
- 项目“D:\workForMy\workspace\ipc_test\build\ipc_testd.vcxproj.metaproj”(3)正在节点 1 上生成“D:\workForMy\workspace\ipc_test\build
- \ipc_testd.vcxproj”(4) (默认目标)。
- PrepareForBuild:
- 正在创建目录“ipc_testd.dir\Debug\”。
- InitializeBuildStatus:
- 正在创建“ipc_testd.dir\Debug\ipc_testd.unsuccessfulbuild”,因为已指定“AlwaysCreate”。
- CustomBuild:
- Building Custom Rule D:/workForMy/workspace/ipc_test/CMakeLists.txt
- CMake does not need to re-run because D:/workForMy/workspace/ipc_test/build/CMakeFiles/generate.stamp is up-to-date.
- MakeDirsForCl:
- 正在创建目录“D:\workForMy\workspace\ipc_test\build\Debug”。
- ClCompile:
- d:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\x86_amd64\CL.exe /c /ID:\workForMy\workspace\ipc_test\ipc
- /I"D:\workForSoftware\Visual Leak Detector\include" /Zi /nologo /W3 /WX- /Od /Ob0 /D WIN32 /D _WINDOWS /D _PLATFORM_I
- S_WINDOWS_ /D "CMAKE_INTDIR=\"Debug\"" /D _MBCS /Gm- /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /GR /F
- o"ipc_testd.dir\Debug\\" /Fd"ipc_testd.dir\Debug\vc100.pdb" /Gd /TP /errorReport:queue ..\ipc\ipcclient.cpp ..\ipc\ip
- cserver.cpp ..\src\main.cpp
- ipcclient.cpp
- ipcserver.cpp
- main.cpp
- Generating Code...
- ManifestResourceCompile:
- C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\rc.exe /nologo /fo"ipc_testd.dir\Debug\ipc_testd.exe.embed.ma
- nifest.res" ipc_testd.dir\Debug\ipc_testd_manifest.rc
- Link:
- d:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\x86_amd64\link.exe /ERRORREPORT:QUEUE /OUT:"D:\workForMy\w
- orkspace\ipc_test\bin\ipc_testd.exe" /INCREMENTAL /NOLOGO /LIBPATH:"D:\workForSoftware\Visual Leak Detector\lib\Win64
- " kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.li
- b /MANIFEST /ManifestFile:"ipc_testd.dir\Debug\ipc_testd.exe.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' u
- iAccess='false'" /DEBUG /PDB:"D:/workForMy/workspace/ipc_test/bin/ipc_testd.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMIC
- BASE /NXCOMPAT /IMPLIB:"D:/workForMy/workspace/ipc_test/bin/Debug/ipc_testd.lib" /MACHINE:X64 ipc_testd.dir\Debug\ipc
- _testd.exe.embed.manifest.res
- ipc_testd.dir\Debug\ipcclient.obj
- ipc_testd.dir\Debug\ipcserver.obj
- ipc_testd.dir\Debug\main.obj /machine:x64
- ipc_testd.vcxproj -> D:\workForMy\workspace\ipc_test\bin\ipc_testd.exe
- Manifest:
- C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\mt.exe /nologo /verbose /out:"ipc_testd.dir\Debug\ipc_testd.e
- xe.embed.manifest" /manifest ipc_testd.dir\Debug\ipc_testd.exe.intermediate.manifest
- C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\rc.exe /nologo /fo"ipc_testd.dir\Debug\ipc_testd.exe.embed.ma
- nifest.res" ipc_testd.dir\Debug\ipc_testd_manifest.rc
- LinkEmbedManifest:
- d:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\x86_amd64\link.exe /ERRORREPORT:QUEUE /OUT:"D:\workForMy\w
- orkspace\ipc_test\bin\ipc_testd.exe" /INCREMENTAL /NOLOGO /LIBPATH:"D:\workForSoftware\Visual Leak Detector\lib\Win64
- " kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.li
- b /MANIFEST /ManifestFile:"ipc_testd.dir\Debug\ipc_testd.exe.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' u
- iAccess='false'" /DEBUG /PDB:"D:/workForMy/workspace/ipc_test/bin/ipc_testd.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMIC
- BASE /NXCOMPAT /IMPLIB:"D:/workForMy/workspace/ipc_test/bin/Debug/ipc_testd.lib" /MACHINE:X64 ipc_testd.dir\Debug\ipc
- _testd.exe.embed.manifest.res
- ipc_testd.dir\Debug\ipcclient.obj
- ipc_testd.dir\Debug\ipcserver.obj
- ipc_testd.dir\Debug\main.obj /machine:x64
- ipc_testd.vcxproj -> D:\workForMy\workspace\ipc_test\bin\ipc_testd.exe
- FinalizeBuildStatus:
- 正在删除文件“ipc_testd.dir\Debug\ipc_testd.unsuccessfulbuild”。
- 正在对“ipc_testd.dir\Debug\ipc_testd.lastbuildstate”执行 Touch 任务。
- 已完成生成项目“D:\workForMy\workspace\ipc_test\build\ipc_testd.vcxproj”(默认目标)的操作。
- 已完成生成项目“D:\workForMy\workspace\ipc_test\build\ipc_testd.vcxproj.metaproj”(默认目标)的操作。
- 已完成生成项目“D:\workForMy\workspace\ipc_test\build\ipc_test.sln”(默认目标)的操作。
- 已成功生成。
- 0 个警告
- 0 个错误
- 已用时间 00:00:02.99
- D:\workForMy\workspace\ipc_test\build>
启动测试:
本文测试了多次,程序启动后大概执行近2分钟后,按“d”输出打印结果,最终是所有线程、所有数据的写入及读取逻辑顺序都是正确的
四、补充
应部分读者要求,完整代码已经上传CSDN: