Mam problem i nie wiem jak go rozwiazać:/ Otóż w moim programie tworzę poprzez CreatePipe() potok nienazwany no i teraz watek który ma z niego czytać ReadFile() zawiesza się do momentu pojawienia się danych w potoku. No i teraz pytanie jak z takiego blokującego potopu zrobić nieblokujący lub blokujący ale na dany czas? Rozwiązał ktoś taki problem? Pod unixem wiem ale co mi z tego..
Proste. W CreateNamedPipe (czyli nie CreatePipe) użyj flagi FILE_FLAG_OVERLAPPED, a zamiast ReadFile użyj ReadFileEx podając do niej adres funkcji którą system ma wywołać gdy pojawią się dane. Parametr hEvent w strukturze OVERLAPPED nie jest wtedy używany przez system, więc mozesz tam wstawić cokolwiek, np. adres bufora na dane, wskaźnik do klasy itd.
Ale też pamiętaj że wątek musi być w stanie alertable by całość ruszyła - dodatkowy parametr alertable w rozszerzonych funkcjach oczekujących SleepEx, WaitForSingleObjectEx, WaitForMultipleObjectsEx, MsgWaitForMultipleObjectsEx powinien być TRUE.
Przykład 1:
void __stdcall OnReadCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, OVERLAPPED *lpOverlapped)
{
switch (dwErrorCode)
{
case WAIT_IO_COMPLETION:
case ERROR_SUCCESS:
lpOverlapped->hEvent = (HANDLE)dwNumberOfBytesTransfered;
}
}
void CzytajDane(HANDLE hPipeRead, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, DWORD dwTimeout),DWORD
{
OVERLAPPED o = {0};
// zakolejkuj odbiór danych
ReadFileEx(hPipeRead, lpBuffer, nNumberOfBytesToRead, &o, OnReadCompletion);
#if 1 // do wyboru
SleepEx(dwTimeout, TRUE);
if (!o.hEvent) CancelIo(hPipeRead); // anuluj ReadFileEx jeżeli nic nie odebrano
#else
HANDLE hEvent = CreateEvent(0,0,0,0);
if (WaitForSingleObjectEx(hEvent, dwTimeout, TRUE) == WAIT_TIMEOUT)
{
CancelIo(hPipeRead);
}
CloseHandle(hEvent);
#endif
return (DWORD)o.hEvent;
}
MsgWaitForMultipleObjectsEx nada się doskonale gdy wątek czytający z rury ma kolejkę komunikatów, a reszta przytoczonych funkcji nada się do oczekiwania na dane z rury.
Przykład:
HANDLE hEvent = CreateEvent(0,0,0,0); // na potrzeby stanu alertable
while (działaj)
{
DWORD dwWaitStatus = MsgWaitForMultipleObjectsEx(1, &hEvent, INFINITE, QS_ALLPOSTMESSAGE|QS_ALLINPUT, MWMO_ALERTABLE);
switch (dwWaitStatus)
{
//case 0: hEvent zasygnalizowany, ignorujemy. break;
//case WAIT_IO_COMPLETION: ReadFileEx wywołało twój callback, ignorujemy. break;
case 1: // WAIT_OBJECT_0 + pierwszy parametr w MsgWaitForMultipleObjectsEx
// jest nowy komunikat do odebrania
while (PeekMessage(..., PM_REMOVE))
{
// todo
}
break;
}
}
CloseHandle(hEvent);
Jak widać, hEvent jest użyty tylko tutaj. Możesz go użyć np. do przerwania tej pętli wywołując SetEvent(hEvent) gdziekolwiek w programie (oraz dodając obsługę case 0). ReadFileEx po zgłoszeniu napływu danych musisz ponownie wywołać by odebrać następne dane. Możesz to zrobić w powyższej pętli obsługując WAIT_IO_COMPLETION.
Gdy już skończysz z rurą to zrób na niej CancelIo(hPipe) dla świętego spokoju, by system anulował ostatnie ReadFileEx i przypadkiem nie zrobił niebieskiej niespodzianki.
Dziękuję za konkretną odpowiedź:) Trochę szkoda, że to muszą być NamedPipe. Nam nadzieję że uda mi się to jakoś wdrożyć do mojego programu. No i jeszcze jeden problem bo w jednej sytuacji watek musi oczekiwać w nieskończoność a drugiej właśnie pewien okres czasu czy będę zmuszony oddzielny Pipe zrobić? Moje pojęcie o WinAPI jest jak widać blade a dodam że muszę zrobić komunikator sieciowy na UDP co oznacza wykonanie diagnostyki przesłanych informacji. Problematyczna sprawa ale jak się chce studiować to i problemy trzeba rozwiązywać;)
Trudno mi odpowiedzieć nie wiedząc jak to ma działać.
Trochę szkoda, że to muszą być NamedPipe
Ile ich potrzebujesz na wątek/program/sesję (logon session) ? Jeżeli jedną, to nie ma problemu, jeżeli chcesz dwa takie programu uruchomić jenocześie to wygeneryj nazwy dynamicznie - id aktualnego procesu/wątku i może aktualny czas, guid (CoCreateGuid), cokolwiek co jest niepowtarzalne jak uchwyt okna.