Windows 服务中的多线程命名管道会锁定客户端
Multi-threaded named pipe in a Windows service locks up clients
我有一个具有多个命名管道的Windows服务。每个管道都在服务中的单独线程中创建。
有多个客户端从这些管道发送/接收信息。
如果我不使用重叠 I/O,则从两个不同的客户端调用 CallNamedPipe(( 时会出现锁定。我使用了此示例:多线程 MSDN 示例
如果我使用重叠 I/O,则不会获得任何锁定,但我只能有一个使用重叠 I/O 的管道线程。我使用了此示例:使用重叠 I/O 的命名管道
知道为什么吗?
下面是一些没有重叠 I/O 的多线程代码示例。当两个客户端进入测试循环并不断调用管道 PipeA 时,其中一个客户端在调用 CallNamedPipe(( 时立即锁定。
#include "windows.h"
#include <process.h>
#include <strsafe.h>
typedef struct
{
HANDLE hPipe;
}ThreadParams_hPipe;
const DWORD BUFSIZE = 2048;
void Thread_NamedPipeServer_PipeA(void *);
int main()
{
// ... service stuff
_beginthread(Thread_NamedPipeServer_PipeA, 0, 0);
// ... code to wait for svc to end
return 0;
}
void PipeA(LPVOID lpvParam)
{
ThreadParams_hPipe *connect_params = (ThreadParams_hPipe *)lpvParam;
DWORD dwBytesRead, dwReplyBytes, dwWritten;
TCHAR chRead[64] = { 0 }, sReply[16] = { 0 };
HANDLE hPipe = (HANDLE)connect_params->hPipe;
if (hPipe)
{
while (1)
{
BOOL bSuccess = ReadFile(hPipe, chRead, BUFSIZE * sizeof(TCHAR), &dwBytesRead, NULL);
if (!bSuccess || dwBytesRead == 0)
break;
chRead[dwBytesRead / sizeof(TCHAR)] = 0; // If it received a value, if it's not null terminated, then put one here.
StringCchCopy(sReply, 16, L"A");
dwReplyBytes = (lstrlenW(sReply) + 1) * sizeof(TCHAR);
bSuccess = WriteFile(hPipe, sReply, dwReplyBytes, &dwWritten, NULL);
if ((!bSuccess) || (dwReplyBytes != dwWritten))
break;
}
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
}
}
void Thread_NamedPipeServer_PipeA(void *)
{
LPTSTR lpszPipename = TEXT("\\.\pipe\{PipeA}");
HANDLE hPipe;
ThreadParams_hPipe connection_params;
SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, (PACL)NULL, FALSE);
sa.nLength = (DWORD) sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = (LPVOID)&sd; sa.bInheritHandle = TRUE;
while (1)
{
hPipe = CreateNamedPipeW(lpszPipename, PIPE_ACCESS_DUPLEX,PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, 0, &sa);
if (hPipe != INVALID_HANDLE_VALUE)
{
if (ConnectNamedPipe(hPipe, NULL))
{
connection_params.hPipe = hPipe;
_beginthread(PipeA, 0, (LPVOID)&connection_params);
}
else
{
CloseHandle(hPipe);
break;
}
}
}
return;
}
以下是在第二个客户端上运行时冻结在 CallNamedPipe(( 行上的客户端代码:
#include <Windows.h>
#include <tchar.h>
#include <strsafe.h>
DWORD NamedPipe_CallServerPipe(TCHAR *sServer)
{
const DWORD BUFSIZE = 1024;
DWORD cbRead;
DWORD rv = 0;
TCHAR sPipename[BUFSIZE] = {0};
TCHAR sMsgToSend[BUFSIZE] = { 0 };
TCHAR chReadBuf[BUFSIZE] = { 0 };
StringCchPrintf(sPipename, BUFSIZE, L"\\%s\pipe\{PipeA}", sServer);
StringCchCopy(sMsgToSend, BUFSIZE, L"msg from cilent");
BOOL bSuccess = CallNamedPipe(sPipename, sMsgToSend, (DWORD)(_tcslen(sMsgToSend) + 1) * sizeof(TCHAR), chReadBuf, BUFSIZE * sizeof(TCHAR), &cbRead, 20000);
if ((bSuccess) && (chReadBuf[0] == 'A'))
rv = 1;
return rv;
}
int main()
{
DWORD rv;
for (DWORD i=0; i< 1000000; i++)
rv = NamedPipe_CallServerPipe(L"Server1");
return 0;
}
所以死锁/种族/阻塞...无论发生什么,都可以通过调用 CreateThread 而不是调用 _beginthread(( 来缓解和完全修复。
所以重新审视这个...真正修复它的是两块。
#1(更改行:
来自: BOOL bSuccess = ReadFile(hPipe, chRead, BUFSIZE * sizeof(WCHAR), &dwBytesRead, NULL);
至: BOOL bSuccess = ReadFile(hPipe, chRead, 64, &dwBytesRead, NULL);
(因为chRead
只有数组大小 64(
#2(将 hPipe 而不是结构发送到线程:
从: connection_params.hPipe = hPipe; _beginthread(PipeA, 0, (LPVOID)&connection_params);
只是: _beginthread(PipeA, 0, hPipe);
来自: ThreadParams_hPipe *connect_params = (ThreadParams_hPipe *)lpvParam; HANDLE hPipe = (HANDLE)connect_params->hPipe;
只是:HANDLE hPipe = static_cast <HANDLE*> (lpvParam);
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 如何找到锁定Linux futex的C++行
- IPC使用多个管道和分支进程来运行Python程序
- G锁定铸造到基础上会释放模拟行为
- 如何检查线程是否锁定
- 如何在C++中找到active directory中禁用和锁定的窗口帐户
- 我应该在锁定TBitmap画布后解锁它吗
- 如何创建函数管道,以便函数一个接一个地运行?
- Gstreamer 管道从命令 lne 到 c 代码
- 外壳包装器句柄/执行交互式命令管道C++ UNIX
- 将旧管道转换为现代 openGL 时出现问题
- 如何使用管道在父级和子级之间来回传递文件
- 在没有管理员权限的情况下连接到同一网络中的命名管道
- C++ 11 中的锁定是否保证访问数据的新鲜度?
- 在两个线程上读/写 64 位,无互斥/锁定/原子
- 如何在实时应用程序中锁定线程
- 如何测量管道延迟?
- 我如何使用此程序管道多个命令?C++
- 先进先出:一个进程永远不会从管道读取
- Windows 服务中的多线程命名管道会锁定客户端