现在我们来看看线程间的通讯机制。 总的说来一共有三种方法: 使用全局变量 使用Windows消息传递机制 使用事件 上面我们说了线程会共享进程的资源,其中全局变量也包括在内,所以线程可以通过使用全局变量来通讯。但是这种办法的明显的缺点是在有多个线程存取同一个全局变量时,必须考虑同步的问题。譬如:有一个有十个成员变量的结构体,其中一个线程在对起赋值时,假设只更新了五个成员变量的值,这时内核的调度线程剥夺其运行权给另一个线程,这样接下来的线程如果想要用该全局结构体变量,它的值就显然不对了。另外多线程的程序也很难调试,尤其这些错误很隐蔽和很难复现时。如果两个线程都是用户界面线程时,用WINDOWS的消息机制来进行线程间的通讯是比较方便的. 您所要做的只是自定义一些windows消息(注意不要和windows的预定义的消息冲突),然后在线程之间传递可以了。您可以这样来定义消息,把WM_USER(它的值等于0x0400)当作基数,然后顺序地去加序号,譬如: WM_MYCUSTOMMSG equ WM_USER+100h 小于WM_USER 的值是Windows系统的保留值,大于该值留给用户来使用。 如果其中有一个线程是工作者线程的话,那就不能用该种方法来进行通讯了,这是因为工作者线程没有消息队列。您应当用下面这种策略来进行工作者线程和用户界面线程之间的通讯: User interface Thread ------> global variable(s)----> Worker thread Worker Thread ------> custom window message(s) ----> User interface Thread 稍后我们的例子中将讲解这种通讯办法。 最后的办法是事件对象。您可以把事件对象看作是一种标志。如果事件对象的状态是无信号的话,说明该线程正在睡眠或挂起,在该种状态下系统是不会给该线程分配CPU时间片的。当一个线程的状态转成有信号时,WINDOWS就会唤醒该线程并且让它正常运行。 例子: 您可以下载例子并运行thread1.exe,然后激活菜单项"Savage Calculation",然后程序开始执行指令"add eax,eax ",一共执行600,000,000次,您会发现在这个过程当中,用户界面将停止响应,您既不能使用菜单,也不能使用移动窗口。等到计算完成后,会弹出一个对话框,关闭掉对话框后窗口才可以和当初一样正常运行了。 为了避免这种不便,我们把计算的工作放入到一个单独的工作者线程中去,而主窗口仅仅响应用户的活动。您可以看到虽然用户界面的反应比平常时慢了,但还是可以工作的。 .386 .model flat,stdcall option casemap:none WinMain proto :DWORD,:DWORD,:DWORD,:DWORD include /masm32/include/windows.inc include /masm32/include/user32.inc include /masm32/include/kernel32.inc includelib /masm32/lib/user32.lib includelib /masm32/lib/kernel32.lib .const IDM_CREATE_THREAD equ 1 IDM_EXIT equ 2 WM_FINISH equ WM_USER+100h .data ClassName db "Win32ASMThreadClass",0 AppName db "Win32 ASM MultiThreading Example",0 MenuName db "FirstMenu",0 SuccessString db "The calculation is completed!",0 .data? hInstance HINSTANCE ? CommandLine LPSTR ? hwnd HANDLE ? ThreadID DWORD ? .code start: invoke GetModuleHandle, NULL mov hInstance,eax invoke GetCommandLine mov CommandLine,eax invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT invoke ExitProcess,eax WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD LOCAL wc:WNDCLASSEX LOCAL msg:MSG mov wc.cbSize,SIZEOF WNDCLASSEX mov wc.style, CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndProc, OFFSET WndProc mov wc.cbClsExtra,NULL mov wc.cbWndExtra,NULL push hInst pop wc.hInstance mov wc.hbrBackground,COLOR_WINDOW+1 mov wc.lpszMenuName,OFFSET MenuName mov wc.lpszClassName,OFFSET ClassName invoke LoadIcon,NULL,IDI_APPLICATION mov wc.hIcon,eax mov wc.hIconSm,eax invoke LoadCursor,NULL,IDC_ARROW mov wc.hCursor,eax invoke RegisterClassEx, addr wc invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,/ WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,/ CW_USEDEFAULT,300,200,NULL,NULL,/ hInst,NULL mov hwnd,eax invoke ShowWindow, hwnd,SW_SHOWNORMAL invoke UpdateWindow, hwnd .WHILE TRUE invoke GetMessage, ADDR msg,NULL,0,0 .BREAK .IF (!eax) invoke TranslateMessage, ADDR msg invoke DispatchMessage, ADDR msg .ENDW mov eax,msg.wParam ret WinMain endp WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM .IF uMsg==WM_DESTROY invoke PostQuitMessage,NULL .ELSEIF uMsg==WM_COMMAND mov eax,wParam .if lParam==0 .if ax==IDM_CREATE_THREAD mov eax,OFFSET ThreadProc invoke CreateThread,NULL,NULL,eax,/ 0,/ ADDR ThreadID invoke CloseHandle,eax .else invoke DestroyWindow,hWnd .endif .endif .ELSEIF uMsg==WM_FINISH invoke MessageBox,NULL,ADDR SuccessString,ADDR AppName,MB_OK .ELSE invoke DefWindowProc,hWnd,uMsg,wParam,lParam ret .ENDIF xor eax,eax ret WndProc endp ThreadProc PROC USES ecx Param:DWORD mov ecx,600000000 Loop1: add eax,eax dec ecx jz Get_out jmp Loop1 Get_out: invoke PostMessage,hwnd,WM_FINISH,NULL,NULL ret ThreadProc ENDP end start
 
2/2 首页 上一页 1 2 |