WIN32汇编语言教程:第12章 多线程 · 12.3 使用事件对象控制线程(2)

12.3.3 进一步改进计数程序

现在让我们进一步改进前面的计数程序,用事件对象代替暂停标志,用WaitForSingleObject函数代替测试暂停标志的语句,这样就可以解决CPU占用率的问题。改进的步骤如下:

● 在程序初始化的时候用CreateEvent函数建立事件对象,以便当做暂停标志使用。

● 当计数线程开始的时候,使用SetEvent函数将事件的初始状态设置为“置位”。

● 计数循环中使用WaitForSingleObject函数测试事件状态,当不需要暂停的时候,由于事件的状态为“置位”,函数会马上返回,循环继续执行。主线程中通过使用ResetEvent函数将事件复位来暂停线程,因为这时进入WaitForSingleObject函数后不会返回,直到主线程中继续使用SetEvent函数将事件置位为止。

● 退出程序的时候用CloseHandle函数删除事件对象。

修改后的代码在所附光盘的Chapter12\Event目录中,Counter.rc文件并没有改动。改动后的Counter.asm文件如下:

                .386
                .model flat, stdcall
                option casemap :none
;####################################################################
; Include 文件定义
;####################################################################
include       windows.inc
include       user32.inc
includelib    user32.lib
include       kernel32.inc
includelib    kernel32.lib
;####################################################################
; Equ 等值定义
;####################################################################
ICO_MAIN         equ    1000
DLG_MAIN          equ    1000
IDC_COUNTER    equ    1001
IDC_PAUSE     equ    1002
;####################################################################
; 数据段
;####################################################################
                .data?
hInstance     dd    ?
hWinMain          dd    ?
hWinCount     dd    ?
hWinPause     dd    ?
hEvent       dd    ?      ;事件对象句柄
 
dwOption          dd    ?
F_PAUSE       equ    0001h
F_STOP       equ    0002h
F_COUNTING    equ    0004h
                .const
szStop         db     '停止计数',0
szStart        db     '计数',0
;####################################################################
; 代码段
;####################################################################
                .code
;####################################################################
_Counter         proc      uses ebx esi edi,_lParam
 
             or    dwOption,F_COUNTING
                  and    dwOption,not (F_STOP or F_PAUSE)
                 invoke SetEvent,hEvent
                invoke SetWindowText,hWinCount,addr szStop
                 invoke EnableWindow,hWinPause,TRUE
 
                xor    ebx,ebx
                 .while ! (dwOption & F_STOP)
                         inc    ebx
                         invoke SetDlgItemInt,hWinMain,IDC_COUNTER,ebx,FALSE
                        invoke WaitForSingleObject,hEvent,INFINITE
                .endw
 
                 invoke SetWindowText,hWinCount,addr szStart
                 invoke EnableWindow,hWinPause,FALSE
                and    dwOption,not (F_COUNTING or F_STOP or F_PAUSE)
                 ret
 
_Counter          endp
;####################################################################
_ProcDlgMain      proc   uses ebx edi esi hWnd,wMsg,wParam,lParam
                 local  @dwThreadID
 
                 mov    eax,wMsg
;********************************************************************
             .if    eax == WM_COMMAND
                     mov    eax,wParam
                      .if    ax ==  IDOK
                             .if    dwOption & F_COUNTING
                                     invoke SetEvent,hEvent
                                     or    dwOption,F_STOP
                             .else
                                   invoke CreateThread,NULL,0,\
                                             offset _Counter,NULL,\
                                             NULL,addr @dwThreadID
                                     invoke CloseHandle,eax
                             .endif
                      .elseif ax ==  IDC_PAUSE
                             xor    dwOption,F_PAUSE
                             .if    dwOption & F_PAUSE
                                     invoke ResetEvent,hEvent
                             .else
                                     invoke SetEvent,hEvent
                             .endif
                      .endif
;********************************************************************
             .elseif eax == WM_CLOSE
                     invoke CloseHandle,hEvent
                     invoke EndDialog,hWnd,NULL
;********************************************************************
             .elseif eax == WM_INITDIALOG
                     push      hWnd
                     pop    hWinMain
                     invoke GetDlgItem,hWnd,IDOK
                      mov    hWinCount,eax
                     invoke GetDlgItem,hWnd,IDC_PAUSE
                     mov    hWinPause,eax
                     invoke CreateEvent,NULL,TRUE,FALSE,NULL
                     mov    hEvent,eax
;********************************************************************
             .else
                     mov    eax,FALSE
                     ret
             .endif
             mov    eax,TRUE
             ret
 
_ProcDlgMain      endp
;####################################################################
start:
             invoke GetModuleHandle,NULL
             mov    hInstance,eax
             invoke DialogBoxParam,eax,DLG_MAIN,\
                     NULL,offset _ProcDlgMain,NULL
             invoke ExitProcess,NULL
;####################################################################
             end    start

修改以后编译执行,然后打开任务管理器观察程序的CPU占用率就可以发现,当按下 “暂停/恢复”按钮暂停计数后,程序的CPU占用率马上下降到接近零,再次按动按钮恢复计数时,CPU占用率会恢复到原来的数值,这说明程序的运行效率得到了很大的提高。

上页:第12章 多线程 · 12.3 使用事件对象控制线程(1) 下页:第12章 多线程 · 12.4 线程间的同步(1)

第12章 多线程

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号