Консультация № 109029
12.11.2007, 10:54
0.00 руб.
0 3 3
Здравствуйте.
Устанавливаю 2 таймера с разным временем срабатывания. При срабатывании таймеров запускаются 2 разных потоках, которые не могут существовать одновременно, т.к. обращаются к одному ресурсу: последовательному порту. Опрос порта должен работать в отдельных потоках, чтобы в это время был доступен пользовательский интерфейс. Чтобы разрулить эту ситуацию, использую функцию API WaitForSingleObject, которая призывает дождаться завершения одного из потоков, если его дескриптор существует, освободить его дескриптор, открыть другой поток, используя для дескриптора освобождённую переменную ThreadHandle (см. секцию case WM_TIMER). Но при накладках, когда не завершился поток запущенный по одному таймеру, скажем, Timer1, а пришло сообщение WM_TIMER от другого таймера, Timer2, программа виснет на WaitForSingleObject. Если вместо

if(ThreadHandle)WaitForSingleObject(ThreadHandle,INFINITE);

использовать

if(ThreadHandle)break;

тогда непонятно, где делать

CloseHandle(ThreadHandle);

Что не так в логике, как сделать правильно?
Спасибо.


Приложение:
UINT_PTR Timer1=1,Timer2=2;HANDLE ThreadHandle=NULL;char MsgBuffer[16];LRESULT CALLBACK WindowProc(HWND hWin,UINT Message,UINT wParam,LONG lParam){ SYSTEM_INFO SysInfo; static DWORD ThId=0; switch(Message){ case WM_CREATE: // Не существенно для понимания логики... break; case WM_TIMER: switch(wParam){ case 1: if(ThreadHandle)WaitForSingleObject(ThreadHandle,INFINITE); CloseHandle(ThreadHandle); ThreadHandle=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RunTV009Thread,(LPVOID)NULL,0,&ThId); if(!ThreadHandle)wsprintf(MsgBuffer,"%d.",GetLastError()); break; case 2: if(ThreadHandle)WaitForSingleObject(ThreadHandle,INFINITE); CloseHandle(ThreadHandle); ThreadHandle=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RunI7052Thread,(LPVOID)NULL,0,&ThId); if(!ThreadHandle)wsprintf(MsgBuffer,"%d.",GetLastError()); default:;} break; case WM_COMMAND: switch(LOWORD(wParam)){ case START_COMMAND: KillTimer(hWin,Timer1); SetTimer(hWin,Timer1,300000,NULL); KillTimer(hWin,Timer2); SetTimer(hWin,Timer2,30000,NULL); break; case STOP_COMMAND: KillTimer(hWin,Timer1); KillTimer(hWin,Timer2); break; case EXIT_COMMAND:SendMessage(hWin,WM_CLOSE,0,0); default:;} break; case WM_CLOSE: case WM_QUIT: case WM_DESTROY: KillTimer(hWin,Timer1); KillTimer(hWin,Timer2); if(ThreadHandle)WaitForSingleObject(ThreadHandle,INFINITE); CloseHandle(ThreadHandle); SendMessage(hStatus,Message,wParam,lParam); PostQuitMessage(0); break; case WM_QUERYENDSESSION: KillTimer(hWin,Timer1); KillTimer(hWin,Timer2); if(ThreadHandle)WaitForSingleObject(ThreadHandle,INFINITE); CloseHandle(ThreadHandle); return 1L; default:return DefWindowProc(hWin,Message,wParam,lParam);} return 0L;}

Обсуждение

Неизвестный
12.11.2007, 11:19
общий
это ответ
Здравствуйте, Arcady0602!
Я думаю, лучше всего будет отказаться от таймеров, поскольку они синхронизируются очередью сообщений, вместо этого использовать потоки, а таймер генерировать слипом на N мс.(например на секунду: Sleep(1000) ) либо ожиданием внешнего события, типа "аборт", на N мс.(второй вариант корректнее, поскольку позволяет выйти из ожидания преждевременно, например при закрытии программы)
Неизвестный
12.11.2007, 12:33
общий
это ответ
Здравствуйте, Arcady0602!
Можно попробовать обойтись без потоков, двумя простыми функциями, которые будут выполняться последовательно. Хотя не всегда это получается.
Неизвестный
12.11.2007, 21:04
общий
это ответ
Здравствуйте, Arcady0602!

В такой схеме стоило бы использовать вместо Wait-INFINITE - цикл и интервал напрммер WaitForSingelObject c 1000 и устанавливать флаг нахождения в данном цикле, тогда приход второго таймера можно просто игнорировать или "отложить" (используя например PostMessage), если флаг сообщает о нахождении в цикле освобождения первого потока по первому таймеру. Надеюсь идея понятна :).
Форма ответа