吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4284|回复: 1
收起左侧

[其他转载] 每天三篇PaPer系列之一,多线程同步问题,学习笔记~~~

 关闭 [复制链接]
baronG 发表于 2010-11-2 12:07
最近定下目标,坚持每天最少三篇paper~
- -
于是有就有了下文~~~
是关于对 多线程同步的一些理解,包括 事件,临界,信号灯,互斥体~
come on~

代码 来自 罗云彬 Win32asm 系列第12章~~
首先
  • hInstance dd ?
  • hWinMain dd ?
  • hWinCount dd ?
  • dwCounter1 dd ?
  • dwCounter2 dd ?
  • dwThreads dd ? ;thread sum
  • hEvent dd ?
  • F_STOP equ 0001h
  • dwOption dd ?

复制代码
对每个变量做以下 解释(从上到下顺序)
1模块 handle
2 窗口 handle
3 按钮handle

4和5 用于 累加的var

6 线程数变量
7 事件 handle

8停止的flag
9 flag的var~~~


go~
  • 004011D4 syn_fix.<模块入口点>                 6A 00                push 0
  • 004011D6                                 E8 63000000          call <jmp.&kernel32.GetModuleHandleA>
  • 004011DB                                 A3 00304000          mov dword ptr ds:[403000],eax
  • 004011E0                                 6A 00                push 0
  • 004011E2                                 68 7F104000          push syn_fix.0040107F                   ; 消息处理过程
  • 004011E7                                 6A 00                push 0
  • 004011E9                                 68 E8030000          push 3E8
  • 004011EE                                 50                   push eax
  • 004011EF                                 E8 08000000          call <jmp.&user32.DialogBoxParamA>
  • 004011F4                                 6A 00                push 0
  • 004011F6                                 E8 3D000000          call <jmp.&kernel32.ExitProcess>
  • ____分割线
  • 0040107F                               /.  55                 push ebp
  • 00401080                               |.  8BEC               mov ebp,esp
  • 00401082                               |.  83C4 FC            add esp,-4
  • 00401085                               |.  53                 push ebx
  • 00401086                               |.  57                 push edi
  • 00401087                               |.  56                 push esi
  • 00401088                               |.  8B45 0C            mov eax,dword ptr ss:[ebp+C]
  • 0040108B                               |.  3D 13010000        cmp eax,113                             ;  Switch (cases 10..113)
  • 00401090                               |.  75 4D              jnz short syn_fix.004010DF
  • 00401092                               |.  6A FF              push -1                                 ; /Timeout = INFINITE; Case 113 (WM_TIMER) of switch 0040108B
  • 00401094                               |.  FF35 18304000      push dword ptr ds:[403018]              ; |hObject = NULL
  • 0040109A                               |.  E8 AB010000        call <jmp.&kernel32.WaitForSingleObject>; \WaitForSingleObject
  • 0040109F                               |.  6A 00              push 0                                  ; /IsSigned = FALSE
  • ....
  • ...
  • ..

复制代码
首先 我们先看 dlg初始化消息的处理~
源代码~


.elseif eax == WM_INITDIALOG
                                
                                push hWnd
                                pop hWinMain
                                invoke GetDlgItem,hWnd,IDC_BTN1
                                mov hWinCount,eax; 给我控制室的联系方式~~
                                
                                invoke CreateEvent,NULL,FALSE,TRUE,NULL;叫黑丝御姐去协调,那20多个工人的同步问题
                                ;要是一个工人干完了,直接联系下一个工人,同时通知第一个工人,到了就直接工作,谁也不用报告~
                                mov hEvent,eax        

1,保存 窗口句柄
2 获得按钮控件句柄
3 创建一直自动的事件,且为置位,这样第一个线程,在遇到WaitForSingleObject直接就可以开始,不会陷入等待,造成 无法执行下去的 bug~~~
  • 00401186                               |> \3D 10010000        cmp eax,110
  • 0040118B                               |.  75 2F              jnz short syn_fix.004011BC
  • 0040118D                               |.  FF75 08            push dword ptr ss:[ebp+8]               ;  Case 110 (WM_INITDIALOG) of switch 0040108B
  • 00401190                               |.  8F05 04304000      pop dword ptr ds:[403004]               ;  得到窗口句柄存放到数据段
  • 00401196                               |.  68 EB030000        push 3EB                                ; /ControlID = 3EB (1003.)
  • 0040119B                               |.  FF75 08            push dword ptr ss:[ebp+8]               ; |hWnd
  • 0040119E                               |.  E8 65000000        call <jmp.&user32.GetDlgItem>           ; \GetDlgItem
  • 004011A3                               |.  A3 08304000        mov dword ptr ds:[403008],eax           ;  获得 子控件句柄
  • 004011A8                               |.  6A 00              push 0                                  ; /EventName = NULL
  • 004011AA                               |.  6A 01              push 1                                  ; |InitiallySignaled = TRUE
  • 004011AC                               |.  6A 00              push 0                                  ; |ManualReset = FALSE
  • 004011AE                               |.  6A 00              push 0                                  ; |pSecurity = NULL
  • 004011B0                               |.  E8 77000000        call <jmp.&kernel32.CreateEventA>       ; \CreateEventA
  • 004011B5                               |.  A3 18304000        mov dword ptr ds:[403018],eax           ;  控件的句柄
  • 004011BA                               |.  EB 0C              jmp short syn_fix.004011C8

复制代码
接下来看~WM_COMMAND消息的处理
  • 004010E6                               |.  8B45 10            mov eax,dword ptr ss:[ebp+10]           ;  Case 111 (WM_COMMAND) of switch 0040108B
  • 004010E9                               |.  66:3D EB03         cmp ax,3EB                              ;  比较是否是相应的按钮控件
  • 004010ED                               |.  0F85 D5000000      jnz syn_fix.004011C8
  • 004010F3                               |.  833D 14304000 00   cmp dword ptr ds:[403014],0
  •   ;  这里是通过判断dwThread来检测,是要开始计算,还是要停止,如果是已经开始计算了,要停止下来,
  • ;那么这个变量就是非零,反之亦然,如果是非零 就继续向下执行,非零就从0040110F开始执行了
  • 004010FA                               |.  74 13              je short syn_fix.0040110F
  • 004010FC                               |.  830D 1C304000 01   or dword ptr ds:[40301C],1
  • 00401103                               |.  6A 01              push 1                                  ; /TimerID = 1
  • 00401105                               |.  FF75 08            push dword ptr ss:[ebp+8]               ; |hWnd
  • 00401108                               |.  E8 01010000        call <jmp.&user32.KillTimer>            ; \KillTimer
  • 0040110D                               |.  EB 4D              jmp short syn_fix.0040115C
  • 0040110F                               |>  C705 0C304000 0000>mov dword ptr ds:[40300C],0             ;  计数变量清0
  • 00401119                               |.  C705 10304000 0000>mov dword ptr ds:[403010],0
  • 00401123                               |.  33DB               xor ebx,ebx
  • 00401125                               |.  EB 1F              jmp short syn_fix.00401146
  • 00401127                               |>  8D45 FC            /lea eax,dword ptr ss:[ebp-4]           ;  线程ID变量的指针
  • 0040112A                               |.  50                 |push eax                               ; /pThreadId
  • 0040112B                               |.  6A 00              |push 0                                 ; |CreationFlags = 0
  • 0040112D                               |.  6A 00              |push 0                                 ; |pThreadParm = NULL
  • 0040112F                               |.  68 00104000        |push syn_fix.00401000                  ; |ThreadFunction = syn_fix.00401000
  • 00401134                               |.  6A 00              |push 0                                 ; |StackSize = 0
  • 00401136                               |.  6A 00              |push 0                                 ; |pSecurity = NULL
  • 00401138                               |.  E8 F5000000        |call <jmp.&kernel32.CreateThread>      ; \CreateThread
  • 0040113D                               |.  FF75 FC            |push dword ptr ss:[ebp-4]              ; /hObject
  • 00401140                               |.  E8 E1000000        |call <jmp.&kernel32.CloseHandle>       ; \CloseHandle
  • 这里就开始执行线程了。我们到 线程函数里面 看看把~~~
  • 这个是重点~

复制代码
第一条线程创建后 SetWindosText后~
  • 00401149                                         |.  6A 00              push 0                                  ; /如果创建完20条线程以后~我们就创建一个定时器,用以将数值写到控件里面
  • 0040114B                                         |.  68 F4010000        push 1F4                                ; |Timeout = 500. ms
  • 00401150                                         |.  6A 01              push 1                                  ; |TimerID = 1
  • 00401152                                         |.  FF75 08            push dword ptr ss:[ebp+8]               ; |hWnd
  • 00401155                                         |.  E8 BE000000        call <jmp.&user32.SetTimer>             ; \SetTimer
  • 会创建一个定时器 500MS执行一次 WM_TIMER消息~,
  • 0040108B                                         |.  3D 13010000        cmp eax,113                                  ;  Switch (cases 10..113)
  • 00401090                                         |.  75 4D              jnz short syn_fix.004010DF
  • 00401092                                         |.  6A FF              push -1                                      ; /Timeout = INFINITE; Case 113 (WM_TIMER) of switch
  • 00401094                                         |.  FF35 18304000      push dword ptr ds:[403018]                   ; |hObject = 00000064 (window)
  • 0040109A                                         |.  E8 A9010000        call <jmp.&kernel32.WaitForSingleObject>     ; \WaitForSingleObject
  • ;这里同样是用一组 WaitForSingleObject 来等待线程完成 ,才进行下一个线程
  • 0040109F                                         |.  6A 00              push 0                                       ; /IsSigned = FALSE
  • 004010A1                                         |.  FF35 0C304000      push dword ptr ds:[40300C]                   ; |Value = A (10.)
  • 004010A7                                         |.  68 E9030000        push 3E9                                     ; |ControlID = 3E9 (1001.)
  • 004010AC                                         |.  FF35 04304000      push dword ptr ds:[403004]                   ; |hWnd = 00700340 ('同步问题解决',class='#32770')
  • 004010B2                                         |.  E8 5B010000        call <jmp.&user32.SetDlgItemInt>             ; \SetDlgItemInt
  • 004010B7                                         |.  6A 00              push 0                                       ; /IsSigned = FALSE
  • 004010B9                                         |.  FF35 10304000      push dword ptr ds:[403010]                   ; |Value = A (10.)
  • 004010BF                                         |.  68 EA030000        push 3EA                                     ; |ControlID = 3EA (1002.)
  • 004010C4                                         |.  FF35 04304000      push dword ptr ds:[403004]                   ; |hWnd = 00700340 ('同步问题解决',class='#32770')
  • 004010CA                                         |.  E8 43010000        call <jmp.&user32.SetDlgItemInt>             ; \SetDlgItemInt
  • 004010CF                                         |.  FF35 18304000      push dword ptr ds:[403018]                   ; /hEvent = 00000064 (window)
  • 004010D5                                         |.  E8 68010000        call <jmp.&kernel32.SetEvent>                ; \SetEvent
  • ;同样 告诉windows自己搞完了,让别的线程进~~~
  • 004010DA                                         |.  E9 E7000000        jmp syn_fix.004011C6

复制代码
  • 00401025                                         |> /6A FF              /push -1                                     ; /Timeout = INFINITE
  • 00401027                                         |. |FF35 18304000      |push dword ptr ds:[403018]                  ; |hObject = 00000064 (window)
  • 0040102D                                         |. |E8 16020000        |call <jmp.&kernel32.WaitForSingleObject>    ; \WaitForSingleObject
  • ;  这里WaitForSingleObject来判断下一个线程是否能运行,当然因为我们创建事件的时候是置位的,所以第一条线程顺利运行.....其他的事件就会等待在这里
  • 00401032                                         |. |FF05 0C304000      |inc dword ptr ds:[40300C]
  • 00401043                                         |.  FF35 18304000      |push dword ptr ds:[403018]                  ; /hEvent = 00000064 (window)
  • 00401049                                         |.  E8 F4010000        |call <jmp.&kernel32.SetEvent>               ; \SetEvent
  • ;等到线程要运行的执行运行完,我们就使用SetEvent置位,相当于告诉windows,我做完了,让别的线程进来 XXOO把~~~~

复制代码
OK事件搞完了~~~
我们看一下 临界区~~~
  • 临界区实现的是互斥技术。在任何时刻,只有一个线程能进入临界区。只有在该线程离开临界区后,其它线程才能进入。临界区对象不能被移动或者拷贝,进程也不能够修改该对象,而必须把它看作逻辑上不透明的(小黑箱)。使用由Win32 API提供的临界区函数来管理临界区对象。
  •     要使用临界区,首先需要定义一个临界区对象,此时,进程负责分配相应内存:
  •         CRITICAL_SECTION cs;
  •     然后,临界区对象必须由程序中某个线程初始化:
  •         InitializeCriticalSection(&cs);
  •     当初始化完该临界区对象后,线程可以调用下面的函数进入临界区:
  •         EnterCriticalSection (&cs);
  •     进入临界区后,该线程被认为拥有该入临界区对象。因此,其它线程调用EnterCriticalSection想进入该入临界区时,会被挂起。赶到拥有临界区对象的线程离开临界区后,它才有机会获得该临界区对象。一旦一个线程拥有临界区,那么它可以再调用EnterCriticalSection或者TryEnterCriticalSection而不会阻塞它自己的执行。这防止了一个线程因等待它自己所拥有的临界区而出现死锁。(TryEnterCriticalSection与TryEnterCriticalSection的区别:前者无论是否获得临界区,都立即返回;而后者在获得临界区前一直处理阻塞状态。TryEnterCriticalSection可以通过函数的返回值判断是否获得临界区,如果没有,可以做其它事情,而不是处于等待状态。)
  •     离开临界区:
  •         LeaveCriticalSection(&cs);
  •     当临界区不再需要时,可将其删除,从而释放相应系统资源:
  •         DeleteCriticalSection (&cs);
  •     使用临界区有一个限制,它只能用于同一进程内的线程间的互斥。而在某些情况下,需要协调两个不同进程对同一资源的共享(如共享内存)。此时,已不能再使用临界区做到,需要借助于互斥对象(mutex object)来实现(注:mutex是一个合成词[mutual exclusion])。

复制代码

理论我是从 网上直接粘贴的 - - 大家直接看把~~~
就是定义了 一个 CRITIGAL_SECTION 结构
然后初始化,然后 EnterCriticalSection 一下,这样 就保证了 只有一条线程可以操作 指令,剩下的执行到这里 就被挂起了。 嘿嘿



还是看OD~~
  • 线程
  • 标识       入口       数据块       最后错误            状态        优先权     用户时间      系统时间
  • 0000009C   7C810856   7FF99000     ERROR_SUCCESS (000  激活           32 + 0       1.1875 s      0.0468 s
  • 000000F8   7C810856   7FFD3000     ERROR_SUCCESS (000  激活           32 + 0       0.0937 s      0.4531 s
  • 00000344   7C810856   7FFD5000     ERROR_SUCCESS (000  激活           32 + 0       0.0937 s      0.6718 s
  • 0000055C   7C810856   7FF9B000     ERROR_SUCCESS (000  激活           32 + 0       1.4218 s      0.0781 s
  • 00000560   7C810856   7FFDC000     ERROR_SUCCESS (000  激活           32 + 0       0.0312 s      0.5000 s
  • 00000654   7C810856   7FFDA000     ERROR_SUCCESS (000  激活           32 + 0       0.0312 s      0.4218 s
  • 0000071C   7C810856   7FFDB000     ERROR_SUCCESS (000  激活           32 + 0       0.7968 s      0.0937 s
  • 00000748   7C810856   7FFD4000     ERROR_SUCCESS (000  激活           32 + 0       1.0625 s      0.0625 s
  • 00000908(  004011C1   7FFDF000     ERROR_ACCESS_DENIE  激活           32 + 0       0.0468 s      0.1093 s
  • 000009A8   7C810856   7FF9A000     ERROR_SUCCESS (000  激活           32 + 0       0.1093 s      0.9218 s
  • 00000A24   7C810856   7FF9D000     ERROR_SUCCESS (000  激活           32 + 0       0.9062 s      0.1093 s
  • 00000AF0   7C810856   7FFD9000     ERROR_SUCCESS (000  激活           32 + 0       1.1562 s      0.0468 s
  • 00000B00   7C810856   7FFD7000     ERROR_SUCCESS (000  激活           32 + 0       1.0937 s      0.0312 s
  • 00000BA4   7C810856   7FF9C000     ERROR_SUCCESS (000  激活           32 + 0       0.1093 s      0.4531 s
  • 00000CE8   7C810856   7FFD8000     ERROR_SUCCESS (000  激活           32 + 0       0.1406 s      0.7031 s
  • 00000D10   7C810856   7FF9E000     ERROR_SUCCESS (000  激活           32 + 0       0.1406 s      0.6093 s
  • 00000D2C   7C810856   7FFDD000     ERROR_SUCCESS (000  激活           32 + 0       1.5468 s      0.0781 s
  • 00000E20   7C810856   7FF98000     ERROR_SUCCESS (000  激活           32 + 0       0.0937 s      0.4531 s
  • 00000E44   7C810856   7FFDE000     ERROR_SUCCESS (000  激活           32 + 0       0.0625 s      0.5000 s
  • 00000F1C   7C810856   7FF97000     ERROR_SUCCESS (000  激活           32 + 0       1.1250 s      0.0625 s
  • 00000F88   7C810856   7FF9F000     ERROR_SUCCESS (000  激活           32 + 0       1.2187 s      0.0781 s

复制代码
这里可以看到 所有线程还都是激活的 ,当我们运行 EnterCriticalsection后 我们看

线程
标识       入口       数据块       最后错误            状态        优先权     用户时间      系统时间
0000009C   7C810856   7FF99000     ERROR_SUCCESS (000  暂停           32 + 0       1.1875 s      0.0468 s
000000F8   7C810856   7FFD3000     ERROR_SUCCESS (000  暂停           32 + 0       0.0937 s      0.4531 s
00000344   7C810856   7FFD5000     ERROR_SUCCESS (000  暂停           32 + 0       0.0937 s      0.6718 s
0000055C   7C810856   7FF9B000     ERROR_SUCCESS (000  暂停           32 + 0       1.4218 s      0.0781 s
00000560   7C810856   7FFDC000     ERROR_SUCCESS (000  暂停           32 + 0       0.0312 s      0.5000 s
00000654   7C810856   7FFDA000     ERROR_SUCCESS (000  暂停           32 + 0       0.0312 s      0.4218 s
0000071C   7C810856   7FFDB000     ERROR_SUCCESS (000  暂停           32 + 0       0.7968 s      0.0937 s
00000748   7C810856   7FFD4000     ERROR_SUCCESS (000  暂停           32 + 0       1.0625 s      0.0625 s
00000908(  004011C1   7FFDF000     ERROR_ACCESS_DENIE  暂停           32 + 0       0.0468 s      0.1093 s
000009A8   7C810856   7FF9A000     ERROR_SUCCESS (000  暂停           32 + 0       0.1093 s      0.9375 s
00000A24   7C810856   7FF9D000     ERROR_SUCCESS (000  暂停           32 + 0       0.9062 s      0.1093 s
00000AF0   7C810856   7FFD9000     ERROR_SUCCESS (000  暂停           32 + 0       1.1562 s      0.0468 s
00000B00   7C810856   7FFD7000     ERROR_SUCCESS (000  暂停           32 + 0       1.0937 s      0.0312 s
00000BA4   7C810856   7FF9C000     ERROR_SUCCESS (000  暂停           32 + 0       0.1093 s      0.4531 s
00000CE8   7C810856   7FFD8000     ERROR_SUCCESS (000  暂停           32 + 0       0.1406 s      0.7031 s
00000D10   7C810856   7FF9E000     ERROR_SUCCESS (000  暂停           32 + 0       0.1406 s      0.6093 s
00000D2C   7C810856   7FFDD000     ERROR_SUCCESS (000  暂停           32 + 0       1.5468 s      0.0781 s
00000E20   7C810856   7FF98000     ERROR_SUCCESS (000  暂停           32 + 0       0.0937 s      0.4531 s
00000E44   7C810856   7FFDE000     ERROR_SUCCESS (000  激活           32 + 0       0.0625 s      0.5000 s
00000F1C   7C810856   7FF97000     ERROR_SUCCESS (000  暂停           32 + 0       1.1250 s      0.0625 s
00000F88   7C810856   7FF9F000     ERROR_SUCCESS (000  暂停           32 + 0       1.2187 s      0.0781 s
只有一条线程运行的

执行 LeaveCriticalsection后~~


线程
标识       入口       数据块       最后错误            状态        优先权     用户时间      系统时间
000002A0   7C810856   7FFDE000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
000002E8   7C810856   7FFD6000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
000005A8   7C810856   7FFD9000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
000007E4   7C810856   7FFD4000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000854(  004011C1   7FFDF000     ERROR_SUCCESS (000  激活           32 + 0       0.0625 s      0.1875 s
0000086C   7C810856   7FFDA000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000880   7C810856   7FF97000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000890   7C810856   7FFD3000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000904   7C810856   7FF9E000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
0000095C   7C810856   7FFD5000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000AC8   7C810856   7FF9B000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000B54   7C810856   7FFD8000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000B64   7C810856   7FF9D000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000B84   7C810856   7FF99000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000D44   7C810856   7FF9C000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000DAC   7C810856   7FFDC000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000E88   7C810856   7FF9F000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000EF0   7C810856   7FFD7000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000F6C   7C810856   7FF98000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s
00000F84   7C810856   7FFDD000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0156 s
00000F8C   7C810856   7FF9A000     ERROR_SUCCESS (000  激活           32 + 0       0.0000 s      0.0000 s

当再次有任何一条 线程执行到Enter的时候~~~ ,enter就会把剩下的线程,都挂起。,保证了同步~~~



我们再来看 互斥体

  • windows api中提供了一个互斥体,功能上要比临界区强大。
  • Mutex是互斥体的意思,当一个线程持有一个Mutex时,其它线程申请持有同一个Mutex会被阻塞,
  • 因此可以通过Mutex来保证对某一资源的互斥访问(即同一时间最多只有一个线程访问)。
  • 调用CreateMutex可以创建或打开一个Mutex对象,
  • HANDLE CreateMutex(
  •   LPSECURITY_ATTRIBUTES lpMutexAttributes,
  •   BOOL bInitialOwner,
  •   LPCTSTR lpName
  • );
  • 其中参数lpMutexAttributes用来设定Mutex对象的安全描述符和是否允许子进程继承句柄。
  • bInitialOwner表明是否将Mutex的持有者设置为调用线程。
  • lpName参数设置Mutex的名字,该名字区分大小写并不能包含"",最大长度为MAX_PATH,可设置为NULL表明该Mutex为匿名对象。
  • 如果调用成功,则返回Mutex的句柄,否则返回NULL,如果lpName不为NULL且调用前同名的Mutex已被创建,则返回同名Mutex的句柄,此时调用GetLastError将返回ERROR_ALREADY_EXISTS,参数bInitialOwner将被忽略。

复制代码

理论大家自己 去 msdn google baidu ...
- -
我们再使用Mutext的时候 要使用 先获取互斥量,
获取互斥量 我们使用WaitForSingleObject
当互斥量被等待成功,他将自动复位

其他线程等待
,线程使用完后,调用
ReleaseMutex,hMutex
释放后,互斥量自动置位,此时 其他线程可以进入~~~



- - 就是 代码写的不一样
CreateMutex
WaitForSingleObject
ReleaseMutex
- -
很简单~~


——————
信号灯有点不一样~~


  • Semaphore是旗语的意思,在Windows中,Semaphore对象用来控制对资源的并发访问数。Semaphore对象具有一个计数值,当值大于0时,Semaphore被置信号,当计数值等于0时,Semaphore被清除信号。每次针对Semaphore的wait functions返回时,计数值被减1,调用ReleaseSemaphore可以将计数值增加 lReleaseCount 参数值指定的值。
  • CreateSemaphore函数用于创建一个Semaphore
  • HANDLE CreateSemaphore(
  • LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
  • LONG lInitialCount, 这个就是指示创建后,信号灯对象的计数值,这里我们只需要一个就设置为1
  • LONG lMaximumCount, ;这个是最多,多少个线程能获取这个 计数值
  • LPCTSTR lpName
  • );
  • lpSemaphoreAttributes为安全属性,
  • lInitialCount为Semaphore的初始值,
  • lMaximumCount为最大值,
  • lpName为Semaphore对象的名字,NULL表示创建匿名Semaphore
  • 此外还可以调用OpenSemaphore来打开已经创建的非匿名Semaphore
  • HANDLE OpenSemaphore(
  • DWORD dwDesiredAccess,
  • BOOL bInheritHandle,
  • LPCTSTR lpName
  • );
  • 调用ReleaseSemaphore增加Semaphore计算值
  • BOOL ReleaseSemaphore(
  • HANDLE hSemaphore,
  • LONG lReleaseCount,
  • LPLONG lpPreviousCount
  • );
  • lpReleaseCount参数表示要增加的数值,
  • lpPreviousCount参数用于返回之前的计算值,如果不需要可以设置为NULL

复制代码



当然还是用 WaitForSingleObject 等待到信号灯后,会把信号灯计数-1,这里我们 直接
创建的时候,初始化值,和最大值 都设置为1 ,那么 一个线程进入后,计数值就会-1 == 0,那么 状态变成 复位,其他的线程就等待这里了
执行到最后 调用
ReleaseSemaphore函数
ReleaseSemaphore 函数会把计数值 +1
那么 对象状态又变成置位,那么,其他线程就可进入执行了~~~
- - 如此反复。。

写完了~~~..

笔记只是,一点愚见,
错误的地方,还请各位多多批评和指出
欢迎指导

然后我说完了~~~

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

czjh2008 发表于 2010-11-2 13:43
我最近也在学这个,不错!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-17 01:33

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表