nieblokujący PIPE

0

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

0

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.

0

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ć;)

0

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.

1 użytkowników online, w tym zalogowanych: 0, gości: 1