Funkcja WaitNamedPipe
umożliwia aplikacji klienta przewodów synchroniczne oczekiwanie na dostępne połączenie na określonym serwerze potoku. Następnie wywołujesz CreateFile
, aby otworzyć potok jako klient. Pseudokod:Co to jest nakładająca się operacja we/wy dla WaitNamedPipe?
// loop works around race condition with WaitNamedPipe and CreateFile
HANDLE hPipe;
while (true) {
if (WaitNamedPipe says connection is ready) {
hPipe = CreateFile(...);
if (hPipe ok or last error is NOT pipe busy) {
break; // hPipe is valid or last error is set
}
} else {
break; // WaitNamedPipe failed
}
}
Problemem jest to, że wszystkie one są synchroniczne, blokowanie połączeń. Jaki jest dobry sposób na wykonanie tego asynchronicznie? Nie mogę na przykład znaleźć API, które wykorzystuje na przykład nakładające się operacje wejścia/wyjścia. Na przykład dla serwerów serwery udostępniają parametry lpOverlapped
pozwalające serwerowi na asynchroniczne oczekiwanie na klienta. Serwer rur może następnie zadzwonić pod numer WaitForMultipleObjects i poczekać, aż operacja I/O zostanie zakończona lub jakiekolwiek inne zdarzenie zostanie zasygnalizowane (na przykład zdarzenie sygnalizujące wątek, aby anulować oczekujące operacje we/wy i zakończyć).
Jedynym sposobem, jaki mogę wymyślić jest wywołanie WaitNamedPipe
w pętli z krótkim, skończonym limitem czasu i sprawdzenie innych sygnałów, jeśli upłynie limit czasu. Alternatywnie, w wywołaniu pętli CreateFile
, sprawdź inne sygnały, a następnie wywołaj Sleep
z krótkim opóźnieniem (lub WaitNamedPipe
). Na przykład:
HANDLE hPipe;
while (true) {
hPipe = CreateFile(...);
if (hPipe not valid and pipe is busy) {
// sleep 100 milliseconds; alternatively, call WaitNamedPipe with timeout
Sleep(100);
// TODO: check other signals here to see if we should abort I/O
} else
break;
}
Ale ta metoda śmierdzi wysokim niebem w mojej opinii. Jeśli rura nie jest dostępna przez jakiś czas, wątek nadal działa - zasysa procesor, zużywa moc, wymaga pozostawienia stron pamięci w pamięci RAM itp. W moim umyśle wątek, który opiera się na Sleep
lub krótkich limitach czasu, nie działa dobrze i jest znakiem niechlujnego programowania wielowątkowego.
Ale jaka jest alternatywa w tym przypadku?
Jednym z oczywistych rozwiązań jest umieszczenie wywołania WaitNamedPipe w osobnym wątku. IIRC, kilka asynchronicznych funkcji IO faktycznie używa wątków pod maską, więc nie jest to tak nieefektywne, jak się wydaje. –
Poinformuj nas więcej o stanie wyścigu, nad którym pracuje ten kod. Kod klienta przykładowy dokumentacja MS mówi, aby najpierw wywołać CreateFile, i tylko wywoływać WaitNamedPipe, jeśli Create nie powiedzie się z Pipe Busy. Zrób to w pętli, z odpowiednim czasem oczekiwania na czekanie. To zawsze działało w moim doświadczeniu. Błąd występuje tylko wtedy, gdy dwóch klientów wybiera jedną rurę, ale nie jest to wyścig. Jeden klient łączy się, a drugi czeka i ponownie próbuje, co jest tym samym, co dzieje się z przykładem Snu, ale czystszy. –
@ Mark: jest w dokumentacji. Kiedy WaitNamedPipe się powiedzie, CreateFile może się nie powieść, ponieważ inny wątek wskoczył jako pierwszy. To stan wyścigu: dwa lub więcej wątków ściga się, aby otworzyć rurę. Zawieszanie pętli działa wokół warunków wyścigu, stąd komentarz w kodzie OP. Nie jest to jednak problem, o który nas prosi. –