Полная дуплексная блокировка именованного канала при записи в - PullRequest
0 голосов
/ 01 апреля 2019

Я пытаюсь использовать один 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;
}

Я могу получить "Привет, труба!" сообщение со стороны сервера на сторону клиента. И я ожидаю набрать какую-нибудь строку на терминале любой программы и нажать клавишу ввода, чтобы увидеть ее с другой стороны.

Однако после сообщения приветствия обе программы будут зависать при вызове WriteFile. Тем временем поток застрял при вызове ReadFile. Как я могу заставить это работать, или я что-то упустил?

1 Ответ

1 голос
/ 01 апреля 2019

, когда файл, созданный для синхронного ввода-вывода (флаг FO_SYNCHRONOUS_IO присутствует в FILE_OBJECT) все Операции ввода-вывода с файлом сериализован - новая операция будет ждать в диспетчере ввода-вывода перед передачей драйверу, пока текущая (если она существует) не будет завершена. одновременно может выполнить только один запрос ввода-вывода. если мы заблокируем чтение в выделенном потоке - все другие запросы ввода-вывода для этого файла будут заблокированы, пока чтение не будет завершено. это связано не только с написанием. даже имя файла запроса / атрибуты будут блокироваться здесь. как результат рендеринга чтение в отдельном случае здесь не поможет - мы блокируем при первой попытке записи. В данном решении используются асинхронные файлы - это позволяет любому количеству операций ввода-вывода выполняться одновременно.

...