WIN32汇编语言教程:第12章 多线程 · 12.4 线程间的同步(2)

                   .if    ax ==  IDOK
                          .if    dwThreads
                                   or    dwOption,F_STOP
                                 invoke KillTimer,hWnd,1
                           .else
                                   mov    dwCounter1,0
                                   mov    dwCounter2,0
                                     xor    ebx,ebx
                                     .while ebx <  10
                                           invoke CreateThread,NULL,0,\
                                                    offset _Counter,NULL,\
                                                   NULL,addr @dwThreadID
                                             invoke CloseHandle,eax
                                             inc ebx
                                     .endw
                                     invoke SetTimer,hWnd,1,500,NULL
                             .endif
                     .endif
;********************************************************************
                  .elseif eax == WM_CLOSE
                          .if    ! dwThreads
                                 invoke EndDialog,hWnd,NULL
                        .endif
;********************************************************************
                 .elseif eax == WM_INITDIALOG
                         push      hWnd
                         pop    hWinMain
                         invoke GetDlgItem,hWnd,IDOK
                       mov    hWinCount,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

目录中的ThreadSynErr.rc文件定义了如图12.3所示的界面。


图12.3 多线程同步的演示程序

ThreadSynErr.rc文件的代码为:

//##################################################################
#include             <resource.h>
//##################################################################
#define ICO_MAIN                 1000
#define DLG_MAIN                 1000
#define IDC_COUNTER1      1001
#define IDC_COUNTER2      1002
//##################################################################
ICO_MAIN         ICON              "Main.ico"
//##################################################################
DLG_MAIN DIALOG 227, 187, 129, 56
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "多线程同步的演示程序"
FONT 9, "宋体"
{
 LTEXT "计数器一:", -1, 7, 7, 40, 8
 LTEXT "计数器二:", -1, 7, 22, 41, 8
 EDITTEXT IDC_COUNTER1, 51, 5, 71, 12, ES_READONLY | WS_BORDER | WS_TABSTOP
 EDITTEXT IDC_COUNTER2, 51, 20, 71, 12, ES_READONLY | WS_BORDER | WS_TABSTOP
 PUSHBUTTON "计数", IDOK, 72, 36, 50, 14
}
//##################################################################

“问题程序”还是用循环计数的功能来演示,程序中设置了两个全局变量dwCounter1和dwCounter2用做计数器,当按下“计数”按钮的时候,程序将两个计数器清零,并且用循环语句建立10个线程来同时执行_Counter线程函数:

      mov    dwCounter1,0
      mov    dwCounter2,0
      xor    ebx,ebx
      .while ebx <  10
             invoke CreateThread,NULL,0,offset _Counter,NULL,\
                     NULL,addr @dwThreadID
             invoke CloseHandle,eax
             inc    ebx
      .endw
      invoke SetTimer,hWnd,1,500,NULL

最后,程序设立一个定时器来定时将计数器值显示到编辑框中。

在线程函数中,使用下面的计算代码:

   .while ! (dwOption & F_STOP)
          inc    dwCounter1
          mov    eax,dwCounter2
          inc    eax
          mov    dwCounter2,eax
   .endw

在这段代码中,递增第一个计数器使用inc指令,由于计算用单条指令完成,所以计数器一不会因为同步问题出错,递增第二个计数器的代码使用了3条指令,首先将原来的计数值取到eax中,递增eax后再写回到变量中,如果不存在多个线程同步的问题,这两种算法的结果是一样的,显示到编辑框中的计数值应该是相等的。

在存在同步问题的情况下,如果线程在mov eax,dwCounter2或者inc eax指令执行后被打断,并且其他线程在这期间修改了dwCounter2的值的话,根据前面的分析,就会有一次计数值被丢失。如果显示到编辑框中的计数值不相等,则证明存在同步的问题,通过比较两个计数值的差值,还可以得知同步问题发生的机会是多少。

好了,大家可能都迫不及待地想看运行结果了吧,结果如图12.3所示,这是程序在笔者的450 MHz的计算机上运行了10秒以后的结果,可以看到,10个线程加起来总共进行了  783 189 430次计算,计数器二却丢失了783 189 430-274 090 739=509 098 691次计数,因为同步问题丢失的计数竟然占了65%,可见这绝对不是偶尔发生一次两次的事情,大家可以想像一下,如果有人往一个银行账户中汇款,三笔汇款中丢了两笔,人们会有何感想呢?

上页:第12章 多线程 · 12.4 线程间的同步(1) 下页:第12章 多线程 · 12.4 线程间的同步(3)

第12章 多线程

版权所有 © 云南伯恩科技 证书:粤ICP备09170368号