2012-03-26 11 views
5

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?

+1

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. –

+0

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. –

+1

@ 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. –

Odpowiedz

4

WaitNamedPipe jest całkowicie bezużyteczny i po prostu użyje całego procesora, jeśli podasz limit czasu i nie będzie na to czekać żaden serwer.

Wystarczy zadzwonić CreateFile kółko z Sleep jak robisz, i przenieść go do innych wątków, jak widać właściwe. Nie ma alternatywy API.

Jedną z korzyści jest zapewnienie, że można połączyć się z nazwaną potokiem, ale wyraźnie nie chce się otwierać połączenia. To śmieci.

Jeśli naprawdę chcesz być dokładny, jedynymi opcjami są

  • Upewnić się, że bez względu na program otwiera nazwany potok jest zawsze dzwoni CreateNamedPipe ponownie natychmiast po jej nazwie jest podłączony do rury.
  • Sprawdź, czy twój program rzeczywiście sprawdza, czy program jest uruchomiony.
  • Jeśli twój zamiar naprawdę nie ma dodatkowych połączeń, nadal dzwoń CreateNamedPipe, a kiedy ktoś się połączy, powiedz im, aby odeszli, dopóki nie czekają danego czasu, zamknij rurę.
+0

Zgaduję, że używa tylko całego procesora, jeśli nic innego nie konkuruje? Powinno to przynajmniej dawać CPU jeden raz na takt zegara. Ma to faktycznie sens - oznacza to, że bazowy protokół nie zapewnia żadnego sposobu ustawiania w kolejce połączeń, co wyjaśnia, dlaczego nie ma wersji asynchronicznej. Tak samo jest z połączeniami TCP. Jeśli serwer nie słucha, nie ma sposobu, aby powiedzieć "Oh, OK, a następnie oddzwoń do mnie, gdy jesteś wolny", po prostu trzeba powtarzać okresowo. –

+0

To tylko zaniedbanie ze strony Microsoftu. Kiedy wywołasz 'WaitNamedPipe' z limitem czasu, jeden z twoich cpus będzie na% 100, dopóki nie powróci - to się nazywa livelock - inne rzeczy będą mogły działać, ale nie będzie żadnych bezczynnych cykli na tym procesorze. Podejrzewam, że naprawią to w ciągu dekady lub dwóch. – fcrick

+0

Po prostu skończyłem z ograniczonym czasem oczekiwania. –

2

Dlaczego serwer nie może po prostu utworzyć więcej potoków? Uderzenie wydajności w opisywanym scenariuszu nie stanowi problemu, jeśli jest rzadkie.

tj. jeśli zwykle jest wystarczająco dużo rur, aby się obejść, co to znaczy, jeśli używasz CreateFile/Sleep zamiast WaitForMultipleObjects? Uderzenie wydajnościowe nie będzie miało znaczenia.

Też muszę zakwestionować potrzebę pokrywania się IO w kliencie. Z iloma serwerami komunikuje się jednocześnie? Jeśli odpowiedź jest mniejsza niż, powiedzmy 10, możesz rozsądnie utworzyć wątek na połączenie.

W gruncie rzeczy mówię, że powodem, dla którego nie ma nałożonego WaitforNamedPipe jest brak uzasadnionego zastosowania, który go wymaga.

+0

Klienci nie mają kontroli nad serwerami i muszą zakładać najgorsze. (W tym konkretnym przypadku serwer obsługuje tylko jednego klienta naraz, ale wydaje mi się, że nawet jeśli serwer obsługiwał wielu klientów naraz, klienci powinni nadal być przygotowani na pełny serwer.) –

+0

@JamesJohnston: czy nie piszesz kod serwera? Nazwane potoki są najczęściej używane przez klientów i serwery napisane razem. –

+0

@Ben Przypadek użycia, który wymaga nakładającej się wersji We/Wy WaitNamedPipe, to miejsce, w którym klient chce coś zrobić podczas oczekiwania, ale umieszczenie oczekiwania we własnym wątku nie jest opcją. To nie jest rzadki przypadek użycia! –