Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

Принудительный разрыв именованного канала - C++

Войти
Регистрация
Восстановить пароль
Другие темы раздела
C++ Рекурсия http://www.cyberforum.ru/cpp-beginners/thread1081942.html
Есть задача, написал решение но ответ неправильный. Задача: Решение: #include <iostream> using namespace std; int a, n, m, t, k, x, y, i, j; void p(int i, int j) { if(i < 0 || j < 0 || i...
C++ Возможно ли у семейства фунций exec получить возвращаемое значение? Возможно ли у семейства фунций exec получить возвращаемое значение? прототип позволяет: int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...);... http://www.cyberforum.ru/cpp-beginners/thread1081907.html
Сформировать новый массив C++
Дан массив a1, ... , a20. Сформировать новый массив b1, ... , b20 , у которого вначале следуют все положительные элементы массива А, затем все отрицательные.
C++ Даны одномерные массивы А и В, длины m и n соответственно
Даны одномерные массивы А и В, длины m и n соответственно. Рассортировать их в порядке возрастания и слить их в один массив длиной m+n.
C++ Дано предложение, слова в котором разделены произвольным числом пробелов http://www.cyberforum.ru/cpp-beginners/thread1081897.html
Дано предложение, слова в котором разделены произвольным числом пробелов. Найти количество слов в предложении, самое длинное и самое короткое слово.
C++ Даны две последовательности: x[1] . x[n] и y[1] . y[k] Даны две последовательности: x ... x и y ... y. Найти максимальную длину последовательности, являющейся последовательностью обеих последовательностей. Количество операций порядка n * k. подробнее

Показать сообщение отдельно
Убежденный
Системный программист
Эксперт С++
15547 / 7055 / 1114
Регистрация: 02.05.2013
Сообщений: 11,467
Завершенные тесты: 1
26.01.2014, 17:52
Все дело в том, что использовать один и тот же хэндл из разных потоков в
общем случае небезопасно. Например, что будет, если поток А все время
будет звать ReadFile, а поток Б - WriteFile ? Система должна как-то
синхронизировать эти обращения к общему объекту, в данном примере это файл.
То есть, сначала будет выполнена ReadFile, потом WriteFile, или наоборот.

Если один поток запустил длительную I/O-операцию и ждет ее завершения, а
второй сразу же после этого вызвал, к примеру, DisconnectNamedPipe, то
ему придется подождать своей очереди. Вот почему в Вашем примере она не
отрабатывает как положено, то есть не разрывает соединение сразу.

Вот, набросал такой примерчик:
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <iostream>
#include <string>
#include <Windows.h>
#include <process.h>
 
 
 
using namespace std;
 
 
 
// #define ABORT_PIPE
 
 
 
unsigned int _stdcall Client_ThreadProc(void * /* pParam */)
{
    cout << "Client: wait 2 seconds..." << endl;
 
    Sleep(2000);
 
    cout << "Client: opening pipe..." << endl;
 
    HANDLE const hPipe = CreateFileW(L"\\\\.\\pipe\\MyPipe-12345",
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);
 
    if (INVALID_HANDLE_VALUE == hPipe)
    {
        DWORD const GLE = GetLastError();
        cerr << "Client: CreateFileW failed with last error " << GLE << "." << endl;
        return 0;
    }
 
    cout << "Client: wait 4 seconds..." << endl;
    Sleep(4000);
 
    cout << "Client: writting into pipe..." << endl;
 
    DWORD nBytes;
 
    if (FALSE == WriteFile(hPipe, "Hello", 6, &nBytes, NULL))
    {
        DWORD const GLE = GetLastError();
        cerr << "Client: WriteFile failed with last error " << GLE << "." << endl;
        return 0;
    }
 
    cout << "Client: write completed, exiting..." << endl;
 
    return 0;
}
 
 
 
unsigned int _stdcall Stopper_ThreadProc(void *pParam)
{
    HANDLE const hPipe = (HANDLE const)pParam;
 
    cout << "Stopper: wait 4 seconds..." << endl;
 
    Sleep(4000);
 
    cout << "Stopper: disconnecting pipe..." << endl;
    
    if (FALSE == DisconnectNamedPipe(hPipe))
    {
        DWORD const GLE = GetLastError();
        cerr << "Stopper: DisconnectNamedPipe failed with last error " << GLE << "." << endl;
        return 0;
    }    
 
    cout << "Stopper: exiting..." << endl;
 
    return 0;
}
 
 
 
int main()
{
    cout << "main: creating pipe..." << endl;
 
    HANDLE const hPipe = CreateNamedPipeW(L"\\\\.\\pipe\\MyPipe-12345",
        PIPE_ACCESS_DUPLEX,
        PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
        PIPE_UNLIMITED_INSTANCES,
        4096, // Output buffer size.
        4096, // Input buffer size.
        NMPWAIT_USE_DEFAULT_WAIT,
        NULL // Security attributes
        );
 
    if (INVALID_HANDLE_VALUE == hPipe)
    {
        DWORD const GLE = GetLastError();
        cerr << "main: CreateNamedPipeW failed with last error " << GLE << "." << endl;
        return 0;
    }
 
    _beginthreadex(NULL, 0, Client_ThreadProc, NULL, 0, NULL);
 
    #ifdef ABORT_PIPE
    _beginthreadex(NULL, 0, Stopper_ThreadProc, hPipe, 0, NULL);
    #endif
 
    if (FALSE == ConnectNamedPipe(hPipe, NULL))
    {
        DWORD const GLE = GetLastError();
        cerr << "main: ConnectNamedPipe failed with last error " << GLE << "." << endl;
        return 0;
    }
 
    cout << "main: client connected..." << endl;
 
    char pBuffer[100];
    DWORD nBytes;
 
    if (FALSE == ReadFile(hPipe, pBuffer, 100, &nBytes, NULL))
    {
        DWORD const GLE = GetLastError();
        cerr << "main: ReadFile failed with last error " << GLE << "." << endl;
        return 0;
    }
 
    cout << "main: read completed [msg = " << pBuffer << "], exiting..." << endl;
 
    if (FALSE == DisconnectNamedPipe(hPipe))
    {
        DWORD const GLE = GetLastError();
        cerr << "main: DisconnectNamedPipe failed with last error " << GLE << "." << endl;
        return 0;
    }
 
    CloseHandle(hPipe);
 
    return 0;
}


Здесь происходит следующее: main создает именованный канал, а затем ожидает
входящих подключений, запуская второй поток, имитирующий работу клиента.
Клиент выдерживает небольшую паузу (2 секунды), затем подключается к каналу,
потом снова выдерживает паузу (4 секунды), записывает сообщение в канал и
завершает работу. main отображает сообщение и тоже завершается.

Если раскомментировать макрос ABORT_PIPE, в игру входит третий поток.
Он зовет DisconnectNamedPipe после того, как клиент подключается к каналу, но
до того, как тот успеет отправить сообщение. Что интересно, на связи клиента и
сервера это почти никак не отображается - клиент все равно отправляет сообщение,
который main успешно принимает и отображает в консоли. Что косвенным образом
подтверждает рассуждения выше о внутренних системных очередях и синхронизации.
А вот DisconnectNamedPipe в main завершается, как и следовало ожидать, ошибкой, так
как функция уже была вызвана в другом потоке, просто выполнена она была не сразу.

Цитата Сообщение от Russian_Dragon Посмотреть сообщение
Методом научного тыка, для моего случая подошла функция
CancelIoEx(this->pipeServer, NULL);
Правда я не понял каким боком она заработала, если я на серверной стороне использую ReadFile(...). Возможно, клиент, реализуемый на C#, использует именно ReadFileEx(...), из-за этого CancelIo(this->pipeServer); и не срабатывал, хотя и ошибку тоже не выдавал.
CancelIo отменяет только те операции, которые были инициированы текущим потоком.
Вот почему ее использование очень ограничено. А у CancelIoEx такого недостатка нет.
Правда, доступна она только в Vista и выше...
0
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru