【问题标题】:Multi-threaded named pipe in a Windows service locks up clientsWindows 服务中的多线程命名管道锁定客户端
【发布时间】:2017-11-10 13:50:42
【问题描述】:

我有一个具有多个命名管道的 Windows 服务。每个管道都在服务内的单独线程中创建。

有多个客户端从这些管道发送/接收信息。

如果我不使用重叠 I/O,我会在从两个不同的客户端调用 CallNamedPipe() 时锁定。我用了这个例子:Multi-threaded MSDN Example

如果我使用重叠 I/O,我不会遇到任何锁定,但我只能有一个使用重叠 I/O 的管道线程。我用了这个例子:Named Pipe using Overlapped 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;
}

【问题讨论】:

  • “锁定”不是一个标准术语,但不幸的是,不清楚您的意思是什么。有“死锁”,即 2 个或更多线程由于相互等待而无法取得进展的状态,还有“阻塞”,它描述了单个线程没有取得进展。
  • 我不确定确切的原因是什么,希望有人能告诉我问题是什么。
  • 你是唯一知道症状的人。我可以告诉你什么可能导致死锁,但我不能告诉你你是否看到了死锁。

标签: c++ multithreading named-pipes


【解决方案1】:

所以死锁/竞争/阻塞...无论可能发生什么,都已通过调用 CreateThread 而不是调用 _beginthread() 得到缓解和完全修复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-11
    • 1970-01-01
    • 2011-03-28
    • 1970-01-01
    相关资源
    最近更新 更多