写入时全双工命名管道锁定
Full duplex named pipe lockup when written to
我正在尝试使用一个 NamedPipe 进行双向 IPC。在我看来(我无法在 MSDN 上找到更多信息),一个全双工管道就足够了。这是我的代码。
//Compiled with these commands during my test:
//g++ -DCLIENT -o client.exe xxx.cpp
//g++ -DSERVER -o server.exe xxx.cpp
#include <iostream>
#include <windows.h>
using namespace std;
DWORD WINAPI ReadingThread(LPVOID a)
{
HANDLE pipe = (HANDLE)a;
BOOL result;
char buffer[256];
DWORD numBytesRead;
while (true)
{
result = ReadFile(pipe, buffer, sizeof(buffer) - 1, &numBytesRead, NULL);
if (result)
{
buffer[numBytesRead] = 0;
cout << "[Thread] Number of bytes read: " << numBytesRead << endl;
cout << "[Thread] Message: " << endl
<< buffer << endl
<< endl;
}
else
{
cout << "[Thread] Failed to read data from the pipe. err=" << GetLastError() << endl;
break;
}
}
return 0;
}
int main(int argc, const char **argv)
{
#ifdef CLIENT
cout << "[Main] Connecting to pipe..." << endl;
HANDLE pipe = CreateFileA("\\.\pipe\PipeTest", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#else
cout << "[Main] Creating an instance of a named pipe..." << endl;
HANDLE pipe = CreateNamedPipeA("\\.\pipe\PipeTest", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE, 1, 0, 0, 0, NULL);
#endif
if (pipe == NULL || pipe == INVALID_HANDLE_VALUE)
{
cout << "[Main] Failed to acquire pipe handle." << endl;
return 1;
}
#ifdef CLIENT
#else
cout << "[Server] Waiting for a client to connect to the pipe..." << endl;
BOOL result = ConnectNamedPipe(pipe, NULL);
if (!result)
{
cout << "[Server] Failed to make connection on named pipe." << endl;
CloseHandle(pipe);
return 1;
}
cout << "[Server] Client is here!" << endl;
{
const char *buf = "Hello pipe!\n";
WriteFile(pipe, buf, strnlen(buf, 30), 0, 0);
}
#endif
CreateThread(0, 0, ReadingThread, pipe, 0, 0);
cout << "[Main] Ready to send data." << endl;
while (true)
{
char buffer[128];
DWORD numBytesWritten = 0;
BOOL result;
cin >> buffer;
if (!strcmp(buffer, "q"))
{
break;
}
cout << "[Main] Writing data to pipe..." << endl;
result = WriteFile(pipe, buffer, strnlen(buffer, _countof(buffer)), &numBytesWritten, 0);
if (result)
{
cout << "[Main] Written " << numBytesWritten << " bytes to the pipe." << endl;
}
else
{
cout << "[Main] Failed to write data to the pipe. err=" << GetLastError() << endl;
}
}
CloseHandle(pipe);
cout << "[Main] Done." << endl;
return 0;
}
我可以从服务器端获取 "Hello pipe!" 消息到客户端。我希望在任一程序的终端上输入一些字符串并按回车键,然后在另一端看到它。
但是在 hello 消息之后,两个程序都会卡在 WriteFile
调用上。同时,线程卡在 ReadFile
调用处。我怎样才能让它发挥作用,还是我遗漏了什么?
当为同步 I/O 创建文件时(标志 FO_SYNCHRONOUS_IO
出现在 FILE_OBJECT
中)all I/O 对文件的操作是序列化 - 新操作将在 I/O 管理器中等待,然后传递给驱动程序,直到当前(如果存在)未完成。在并发中只能执行单个 I/O 请求。如果我们在专用线程中阻塞读取 - 对该文件的所有其他 I/O 请求将被阻塞,直到读取未完成。这关系不仅要写。即使是查询文件 name/attributes 也会阻塞在这里。结果,单独渲染读取在这里无济于事 - 我们在第一次写入尝试时阻塞。这里的解决方案使用异步文件 - 这让任何数量的 I/O 操作同时执行。
Windows 中的命名管道是半双工的。如 Windows 所示 10. MSDN 文档有误。已向 Microsoft 提交更正其文档的请求。
虽然可以在客户端上打开一个管道 "Generic Read | Generic Write" 但您不能同时进行这两项操作。
并且在第一个重叠 IO 之后提交的重叠 IO 将破坏管道。
您可以提交重叠的 io。然后等待它完成。然后提交下一个重叠的io。您不能同时提交重叠的读取和重叠的写入。
根据定义,"Half Duplex"。
我正在尝试使用一个 NamedPipe 进行双向 IPC。在我看来(我无法在 MSDN 上找到更多信息),一个全双工管道就足够了。这是我的代码。
//Compiled with these commands during my test:
//g++ -DCLIENT -o client.exe xxx.cpp
//g++ -DSERVER -o server.exe xxx.cpp
#include <iostream>
#include <windows.h>
using namespace std;
DWORD WINAPI ReadingThread(LPVOID a)
{
HANDLE pipe = (HANDLE)a;
BOOL result;
char buffer[256];
DWORD numBytesRead;
while (true)
{
result = ReadFile(pipe, buffer, sizeof(buffer) - 1, &numBytesRead, NULL);
if (result)
{
buffer[numBytesRead] = 0;
cout << "[Thread] Number of bytes read: " << numBytesRead << endl;
cout << "[Thread] Message: " << endl
<< buffer << endl
<< endl;
}
else
{
cout << "[Thread] Failed to read data from the pipe. err=" << GetLastError() << endl;
break;
}
}
return 0;
}
int main(int argc, const char **argv)
{
#ifdef CLIENT
cout << "[Main] Connecting to pipe..." << endl;
HANDLE pipe = CreateFileA("\\.\pipe\PipeTest", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#else
cout << "[Main] Creating an instance of a named pipe..." << endl;
HANDLE pipe = CreateNamedPipeA("\\.\pipe\PipeTest", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE, 1, 0, 0, 0, NULL);
#endif
if (pipe == NULL || pipe == INVALID_HANDLE_VALUE)
{
cout << "[Main] Failed to acquire pipe handle." << endl;
return 1;
}
#ifdef CLIENT
#else
cout << "[Server] Waiting for a client to connect to the pipe..." << endl;
BOOL result = ConnectNamedPipe(pipe, NULL);
if (!result)
{
cout << "[Server] Failed to make connection on named pipe." << endl;
CloseHandle(pipe);
return 1;
}
cout << "[Server] Client is here!" << endl;
{
const char *buf = "Hello pipe!\n";
WriteFile(pipe, buf, strnlen(buf, 30), 0, 0);
}
#endif
CreateThread(0, 0, ReadingThread, pipe, 0, 0);
cout << "[Main] Ready to send data." << endl;
while (true)
{
char buffer[128];
DWORD numBytesWritten = 0;
BOOL result;
cin >> buffer;
if (!strcmp(buffer, "q"))
{
break;
}
cout << "[Main] Writing data to pipe..." << endl;
result = WriteFile(pipe, buffer, strnlen(buffer, _countof(buffer)), &numBytesWritten, 0);
if (result)
{
cout << "[Main] Written " << numBytesWritten << " bytes to the pipe." << endl;
}
else
{
cout << "[Main] Failed to write data to the pipe. err=" << GetLastError() << endl;
}
}
CloseHandle(pipe);
cout << "[Main] Done." << endl;
return 0;
}
我可以从服务器端获取 "Hello pipe!" 消息到客户端。我希望在任一程序的终端上输入一些字符串并按回车键,然后在另一端看到它。
但是在 hello 消息之后,两个程序都会卡在 WriteFile
调用上。同时,线程卡在 ReadFile
调用处。我怎样才能让它发挥作用,还是我遗漏了什么?
当为同步 I/O 创建文件时(标志 FO_SYNCHRONOUS_IO
出现在 FILE_OBJECT
中)all I/O 对文件的操作是序列化 - 新操作将在 I/O 管理器中等待,然后传递给驱动程序,直到当前(如果存在)未完成。在并发中只能执行单个 I/O 请求。如果我们在专用线程中阻塞读取 - 对该文件的所有其他 I/O 请求将被阻塞,直到读取未完成。这关系不仅要写。即使是查询文件 name/attributes 也会阻塞在这里。结果,单独渲染读取在这里无济于事 - 我们在第一次写入尝试时阻塞。这里的解决方案使用异步文件 - 这让任何数量的 I/O 操作同时执行。
Windows 中的命名管道是半双工的。如 Windows 所示 10. MSDN 文档有误。已向 Microsoft 提交更正其文档的请求。
虽然可以在客户端上打开一个管道 "Generic Read | Generic Write" 但您不能同时进行这两项操作。
并且在第一个重叠 IO 之后提交的重叠 IO 将破坏管道。
您可以提交重叠的 io。然后等待它完成。然后提交下一个重叠的io。您不能同时提交重叠的读取和重叠的写入。
根据定义,"Half Duplex"。