定时器与多线程 SetTimer and Multi-Thread 每个线程独立使用一个定时器
生产者——消费者 模拟程序,需求如下:
将生产者和消费者模拟算法封装在一个动态链接库中,主程序调用相关函数。生产者放入产品和消费者取走产品的速度可调节。
分别用循环队列和栈实现。
一般模拟这个算法都是生产这,消费者各开一个线程,同步访问一个共享缓冲区。但是需求要求能调节速度,我的思路是在
每个线程里单独创建一个定时器,但是Windows下定时器特性是:
每隔定时时间,Windows系统放入一个 WM_TIMER 消息到应用程序的消息队列中。
所以我的解决方案如下:
/* 更改定时器的消息 */
#define WM_SETTIMER WM_USER + 100
/* 生产者线程函数 */
DWORD WINAPI ProducerFunc(LPVOID lpParameter)
{
MSG msg;
UINT producerTimerId;
/* Create a message queue for this thread */
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
producerTimerId = SetTimer(NULL, 0, g_uProducerTimer, NULL);
while(GetMessage(&msg, NULL, 0, 0))
{
if(msg.message == WM_TIMER)
{
WaitForSingleObject(g_hEmptySemaphore, INFINITE);
WaitForSingleObject(g_hMutex, INFINITE);
Producer();
ReleaseMutex(g_hMutex);
ReleaseSemaphore(g_hFullSemaphore, 1, NULL);
}
else if(msg.message == WM_SETTIMER)
{
KillTimer(NULL, producerTimerId);
producerTimerId = SetTimer(NULL, 0, g_uProducerTimer, NULL);
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
KillTimer(NULL, producerTimerId);
return 0;
}
/* 消费者线程函数 */
DWORD WINAPI ConsumerFunc(LPVOID lpParameter)
{
MSG msg;
UINT consumerTimerId;
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
consumerTimerId = SetTimer(NULL, 0, g_uConsumerTimer, NULL);
while(GetMessage(&msg, NULL, 0, 0))
{
if(msg.message == WM_TIMER)
{
WaitForSingleObject(g_hFullSemaphore, INFINITE);
WaitForSingleObject(g_hMutex, INFINITE);
Consumer();
ReleaseMutex(g_hMutex);
ReleaseSemaphore(g_hEmptySemaphore, 1, NULL);
}
else if(msg.message == WM_SETTIMER)
{
KillTimer(NULL, consumerTimerId);
consumerTimerId = SetTimer(NULL, 0, g_uConsumerTimer, NULL);
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
KillTimer(NULL, consumerTimerId);
return 0;
}
---------------------------------------------------------------------------
子线程里如何使用定时器 摘自CSDN
UINT_PTR hTimer = 0;
//定时器消息处理函数
VOID __stdcall TimerProc(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime)
{
KillTimer(NULL,hTimer);
MessageBox(NULL,"Speak in Timer!",":)",MB_OK);
}
//线程函数
DWORD __stdcall ThreadFun(void *)
{
MSG msg;
PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE);
hTimer = SetTimer(NULL,0,10,(TIMERPROC)TimerProc);
while(!PeekMessage(&msg,NULL,WM_TIMER,WM_USER+1,PM_NOREMOVE))
{
OutputDebugString("Not peek message\r\n");
Sleep(100);
}
if(msg.message == (WM_USER+1))
{
//收到主线程发来的消息
OutputDebugString("Rec message\r\n");
}
else
{
//收到定时器消息,派送之
OutputDebugString("what message\r\n");
DispatchMessage(&msg);
}
return 0;
}
//创建线程代码:
DWORD dwThreadId;
HANDLE hThread = NULL;
hThread = CreateThread(NULL,0,ThreadFun,NULL,0,&dwThreadId);
if (hThread == NULL)
{
MessageBox("CreateThread failed.", "main", MB_OK );
}
else
{
OutputDebugString("prepare post message\r\n");
Sleep(1000);//等待线程创建好了
PostThreadMessage(dwThreadId,WM_USER+1,0,0);//给线程发消息
OutputDebugString("Post message ok\r\n");
CloseHandle( hThread );
}
你把PostThreadMessage(dwThreadId,WM_USER+1,0,0);注释掉就可以收到定时器消息了,或者是你在线程里循环的接收消息,否则只能接收到一条。
这是MFC的CWinThread类的实现。 首先创建一个线程 _beginthread(MainThread, DEFAULT_STACK_SIZE, NULL);
然后在MainThread中创建一个看不见的窗口(伪窗口):
WNDCLASS wcl;
HWND hWnd = NULL;
memset(&wcl,0,sizeof(wcl));
if (lpfnWndProc == NULL)
{
return NULL; /*失败*/
}
/*register class*/
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.hbrBackground = NULL;
wcl.hCursor = NULL;
wcl.hIcon = NULL;
wcl.hInstance = NULL;
wcl.lpfnWndProc = MainWindowProc;
wcl.lpszClassName = szWndName;
wcl.lpszMenuName = NULL;
wcl.style = CS_VREDRAW;
if (RegisterClass(&wcl) == 0)
{
return NULL;
}
/*create window*/
hWnd = CreateWindow(szWndName,NULL,WS_POPUP,0,0,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,NULL,NULL);
/*进入消息循环*/
do
{
ret = GetMessage(&msg,NULL,0,0);
if (ret > 0)
{
DispatchMessage(&msg);
}
}while(ret > 0);
DestroySTUNServerWindow(szWndName, s_hSTUNServerWnd);
最后可以在MainWindowProc中处理你的消息了:
LRESULT CALLBACK MainWindowProc(HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
default:
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/247600/blog/100885