生产者——消费者 模拟程序,需求如下:
将生产者和消费者模拟算法封装在一个动态链接库中,主程序调用相关函数。生产者放入产品和消费者取走产品的速度可调节。
分别用循环队列和栈实现。
一般模拟这个算法都是生产这,消费者各开一个线程,同步访问一个共享缓冲区。但是需求要求能调节速度,我的思路是在
每个线程里单独创建一个定时器,但是Windows下定时器特性是:
每隔定时时间,Windows系统放入一个 WM_TIMER 消息到应用程序的消息队列中。
所以我的解决方案如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
/* 更改定时器的消息 */
#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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
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中创建一个看不见的窗口(伪窗口):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
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;
}
|