MFC多线程编程_第1页
MFC多线程编程_第2页
MFC多线程编程_第3页
MFC多线程编程_第4页
MFC多线程编程_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、多线程编程之问题提出作者:韩耀旭下载源代码一、问题的提出编写一个耗时的单线程程序:新建一个基于对话框的应用程序Sing leThr ead ,在主对话框IDD_SINGLETHREAD_DIALO G 添加一个按钮, ID 为 IDC_SLEEP_SIX_SECOND , 标 题 为 “延 时 6 秒 ”, 添 加 按 钮 的 响 应 函 数 , 代 码 如 下 :void CSingleThreadDlg:OnSleepSixSecond()Sleep(6000); / 延 时 6 秒编译并运行应用 程序 ,单 击“延时 6 秒”按钮,你 就会发现在这 6 秒期间程 序 就 象 “死 机 ”

2、一 样 ,不 在 响 应 其 它 消 息 。为 了 更 好 地 处 理 这 种 耗 时 的 操 作 ,我 们 有 必要学习多线程编程。二、多线程概述进程和线程 都是操作系统的 概念。进 程是应 用 程序 的执行实例,每 个进程是 由私有的 虚拟地址空间、代 码、数 据和其它各种系统资源组成,进 程在运行过程 中创建的 资源随着进程的 终止而被销毁,所使用 的 系统资源在进程终止时被释放 或关闭。线程是进程 内部的一 个执行单元。系 统创建好进程后,实际上就启动执行了 该进程的 主执行线程,主 执行线程以函数地址形式,比 如说 main 或 WinMain 函 数, 将程序的启动点提供给 Win

3、dows 系统。主执行线程终止了, 进程也就随之 终止。每一个进程 至少有一 个主执行线程,它无需由用 户去主动创建,是 由系统自 动 创 建 的 。用 户 根 据 需 要 在 应 用 程 序 中 创 建 其 它 线 程 ,多 个 线 程 并 发 地 运 行 于 同 一 个 进 程 中 。一 个 进 程 中 的 所 有 线 程 都 在 该 进 程 的 虚 拟 地 址 空 间 中 ,共 同 使 用 这 些虚拟地址空间、全 局变量和系统资源,所 以线程间的 通讯非常方便,多 线程技 术的 应用 也较为广泛。多线程可以实现并行处理, 避免了某项任务长时间占用 CPU 时间。要说明 的一点是,目前大多

4、数的计算机都是单处理器(CPU )的,为了运行所有这些线 程 , 操作 系统为 每个独立 线程安 排一些 CPU 时间, 操作系 统以轮换 方式向 线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。由此可见,如果 两个非常活跃的线程为了抢夺对CPU的控制权,在线程切换时会消耗很多的CPU 资源,反而会降低系统的性能。这一点在多线程编程时应该注意。Wi n32 SDK 函数支持进行多线程的程序设计,并提供了操作系统原理中的 各种同步、互斥和临界区等操作。Visual C+ 6.0 中,使用MFC类库也实现了 多线程的程序设计,使得多线程编程更加方便。三、Win32 API 对多线程编程

5、的支持Win32 提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以 及通信等工作。下面将选取其中的一些重要函数进行说明。1、HANDLE CreateThread(LPSECURITY_ATTRIBUTESIpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreatio nF lags,LPDWORD lpThreadId);该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄, 其中各参数说明如下:* IpThr

6、eadAttributes :指向一个 SECURIT Y_ATTR IBU TES 结构的指针,该 结构决定了线程的安全属性,一般置为NULL ;* dwStackSize :指定了线程的堆栈深度,一般都设置为0 ;lpStartAddress :表示新线程开始执行时代码所在函数的地址,即线程的 起始地址。一般情况为(LPTHREAD_START_ROUTINE )ThreadFunc , ThreadFunc 是线程 函数名;* lpParam eter :指定了线程执行时传送给线程的32位参数,即线程函数的 参数;* dwCreationF lags :控制线程创建的附加标志,可以取两种

7、值。如果该参 数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该 线程处于挂起状态,并不马 上 执行,直至函数ResumeThread 被调用;* lpThread Id :该参数返回所创建线程的ID ;如果创建成功则返回线程的句柄,否则返回NULL。2、DWORD SuspendThread(HANDLE hThread);该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止。3、DWORD ResumeThread(HANDLE hThread);该函数用于结束线程的挂起状态,执行线程。4、VOID ExitThread(D

8、WORD dwExitCode);该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数 dwEx itCode 用来设置线程的退出码。5、BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);一般情况下,线程运行结束之后,线程函数正常返回,但是应用程序可以调 用Term in ateThread 强行终止某一线程的执行。各参数含义如下:« hThread :将被终结的线程的句柄;« dwEx itCode :用于指定线程的退出码。使用Term in ateThread() 终止某个线程的执行是不安全的,可

9、能会引起系统 不稳定;虽然该函数立即终止线程的执行,但并不释放线程所占用的资源。因此, 一般不建议使用该函数。6、BOOL PostThreadMessage(DWORD idThread,UINT Msg, WPARAM wParam, LPARAM lParam);该函数将一条消息放入到指定线程的消息队列中,并且不等到消息被该线程处理 时便返回。idThread :将接收消息的线程的ID ; Msg :指定用来发送的消息;« wParam :同消息有关的字参数;* lPar am :同消息有关的长参数;调用该函数时,如果即将接收消息的线程没有创建消息循环,则该函数执行失败。四、W

10、in32 API 多线程编程例程例程 1 Mu lt iThread11. 建立一个基于对话框的工程Mu It iThread1 ,在对话框IDD_MULT IT HREAD1_DIALOG 中加入两个按钮和一个编辑框,两个按钮 的ID分别是IDC_START ,IDC_STOP ,标题分别为 启动” 停止” IDC_STOP 的 属 性选中Disab led ;编辑框 的ID为IDC_TIME ,属 性选中 Read-only ;2. 在 Mu lt iThread1D lg.h 文件中添加线 程函数 声明 :3. void ThreadFunc();注 意 , 线 程 函 数 的 声 明

11、应 在 类 CMult iThr ead1Dlg 的 外 部 。 在 类CMult iThr ead1Dlg 内 部 添 加 protected 型 变 量 :HANDLE hThread;DWORD ThreadID;分 别 代 表 线 程 的 句 柄 和 ID 。4. 在 Mu lt iThread1D lg.cpp 文 件 中 添 加 全 局 变 量 m_bRun :5. volatile BOOL m_bRun;m_bRun 代 表 线 程 是 否 正 在 运 行 。你 要 留 意 到 全 局 变 量 m_bRun 是 使 用 volat ile 修 饰 符 的 , volat ile

12、 修 饰 符 的 作 用 是 告 诉 编 译 器 无 需 对 该 变 量 作 任 何 的 优 化 ,即 无 需 将 它 放 到 一 个 寄存器中,并且该值可被外部改变。对于多线程引用的全局变量来说, v olatile 是 一 个 非 常 重 要 的 修 饰 符 。编写线程函数:void ThreadFunc()CTime time;CString strTime;m_bRun=TRUE;while(m_bRun)time=CTime:GetCurrentTime(); strTime=time.Format("%H:%M:%S");:SetDlgItemText(AfxG

13、etMainWnd()->m_hWnd,IDC_TIME,strTime);Sleep(1000);该 线 程 函 数 没 有 参 数 ,也 不 返 回 函 数 值 。只 要 m_bRun 为 TRUE ,线 程 一 直运行。双 击 IDC_START 按 钮 , 完 成 该 按 钮 的 消 息 函 数 :void CMultiThread1Dlg:OnStart()/ TODO: Add your control notification handler code here hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thre

14、adFunc,NULL,0,&ThreadID);GetDlgItem(IDC_START)->EnableWindow(FALSE); GetDlgItem(IDC_STOP)->EnableWindow(TRUE);双 击 IDC_STOP 按 钮 , 完 成 该 按 钮 的 消 息 函 数 :void CMultiThread1Dlg:OnStop()/ TODO: Add your control notification handler code here m_bRun=FALSE;GetDlgItem(IDC_START)->EnableWindow(TR

15、UE); GetDlgItem(IDC_STOP)->EnableWindow(FALSE);编 译 并 运 行 该 例 程 , 体 会 使 用 Win32 API 编 写 的 多 线 程 。例 程 2 Mu lt iThread2该线 程演示 了如何传 送一个 一个整 型的参 数到一个线程中 ,以及如 何等待一 个线程完成处理。1. 建 立 一 个 基 于 对 话 框 的 工 程 Mult iThread2 , 在 对 话 框IDD_MULT IT HREAD2_DIALOG 中加入 一 个 编 辑 框 和 一个按 钮 ,ID 分 别是 IDC_COUNT , IDC_START ,按

16、 钮控件的 标题为 “开 始”;2. 在 Mu lt iThread2D lg.h 文件中添加线 程函数 声明 :3. void ThreadFunc(int integer);注 意 , 线 程 函 数 的 声 明 应 在 类 CMult iThr ead2Dlg 的 外 部 。在 类 CMult iThr ead2Dlg 内 部 添 加 protected 型 变 量 :HANDLE hThread;DWORD ThreadID;分 别 代 表 线 程 的 句 柄 和 ID 。在4. 打 开 ClassW izard ,为 编 辑 框 IDC_COUNT 添 加 int 型 变 量 m_n

17、Count Mu lt iThread2D lg.cpp 文 件 中 添 加 :.9.10.11.void ThreadFunc(int integer)int i; for(i=0;i<integer;i+) Beep(200,50);Sleep(1000);12.13.双击IDCSTART按钮,完成该按钮的消息函数:void CMultiThread2Dlg:OnStart()UpdateData(TRUE);int integer=m_nCount; hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadF

18、unc,(VOID*)integer,0,&ThreadID); GetDlgItem(IDC_START)->EnableWindow(FALSE); WaitForSingleObject(hThread,INFINITE); GetDlgItem(IDC_START)->EnableWindow(TRUE);顺 便 说 一 下 W aitForSing leObject 函 数 , 其 函 数 原 型 为 :DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);o hHandle 为 要 监 视

19、的 对 象( 一 般 为 同 步 对 象 ,也 可 以 是 线 程 )的 句 柄;o dwMilliseconds 为 hHand le 对 象 所 设 置 的 超 时 值 , 单 位 为 毫 秒 ;当在 某一线程 中调用 该函数 时,线 程暂时挂起,系 统监 视 hHand le 所 指 向 的 对 象 的 状 态 。如 果 在 挂 起 的 dwMillis econds 毫 秒 内 ,线 程 所 等 待 的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达 dwMilliseconds 毫 秒 , 但 hHand le 所 指 向 的 对 象 还 没 有 变 成 有 信 号 状 态

20、 , 函 数 照 样 返 回 。 参 数 dwMilliseconds 有 两 个 具 有 特 殊 意 义 的 值 : 0 和 INF IN ITE 。若为 0,则该 函数立即 返回;若为 INF INITE ,则 线程一 直被 挂 起 , 直 到 hHandle 所 指 向 的 对 象 变 为 有 信 号 状 态 时 为 止 。本例 程调用该 函数的 作用是 按下 IDC_START 按钮后, 一直 等 到线程 返 回 , 再 恢 复 IDC_START 按 钮 正 常 状 态 。 编 译 运 行 该 例 程 并 细 心 体 会 。例 程 3 Mu lt iThread3传送一个 结构体 给

21、一个线 程函数 也是可 能的,可 以 通过传 送一个 指向结 构体的指 针参数来完成。先定义一个结构体:typedef structint firstArgu,long secondArgu,myType,*pMyType;创建线程时CreateThread(NULL,O,threadFu nc,pMyType,);在 threadFunc 函 数 内 部 , 可 以 使 用 “强 制 转 换 ”:int intValue=(pMyType)lpvoid)->firstArgu;long longValue=(pMyType)lpvoid)->seconddArgu;例 程 3 M

22、u lt iThread3 将 演 示 如 何 传 送 一 个 指 向 结 构 体 的 指 针 参 数 。1. 建立一个基于对话框的工程 Mu lt iThread3 ,在对话框 IDD_MULT IT HREAD3_DIALOG 中加入一个编辑框 IDC_MILL ISECOND ,一 个按钮 IDC_START ,标题为“开始” ,一个进度条 IDC_PROGRESS1 ;2. 打开 ClassW izard ,为编辑框 IDC_MILL ISECOND 添加 int 型变量 m_nMilliSecond ,为进度条 IDC_PROGRESS1 添加 CProgressCtrl 型变量 m

23、_ctrlProgress ;3. 在 Mu lt iThread3D lg.h 文件中添加一个结构的定义:4. struct threadInfo5. 6. UINT nMilliSecond;7. CProgressCtrl* pctrlProgress;8. ;线程函数的声明:UINT ThreadFunc(LPVOID lpParam);注意,二者应在类 CMult iThr ead3Dlg 的外部。在类 CMult iThr ead3Dlg 内部添加 protected 型变量 :HANDLE hThread;DWORD ThreadID;分别代表线程的句柄和 ID 。9. 在 Mu

24、 lt iThread3D lg.cpp 文件中进行如下操作:定义公共变量 threadIn fo Info ; 双击按钮 IDC_START ,添加相应消息处理函数:10.void CMultiThread3Dlg:OnStart()11.12./ TODO: Add your control notificationhandler codehere13.14.UpdateData(TRUE);15.Info.nMilliSecond=m_nMilliSecond;16.Info.pctrlProgress=&m_ctrlProgress;17.18.hThread=CreateTh

25、read(NULL,19.0,20.(LPTHREAD_START_ROUTINE)ThreadFunc,21.&Info,22.0,23.&ThreadID);24. /*25.GetDlgItem(IDC_START)->EnableWindow(FALSE);26.WaitForSingleObject(hThread,INFINITE);27.GetDlgItem(IDC_START)->EnableWindow(TRUE);28. */29. 在 函 数 BOOL CMu lt iThread3Dlg:OnIn itDialog() 中 添 加 语 句 :

26、/ TODO: Add extra initialization here m_ctrlProgress.SetRange(0,99); m_nMilliSecond=10; UpdateData(FALSE);toreturn TRUE; / return TRUE unless you set the focus a control添 加 线 程 处 理 函 数 : UINT ThreadFunc(LPVOID lpParam) threadInfo* pInfo=(threadInfo*)lpParam; for(int i=0;i<100;i+)int nTemp=pInfo-&

27、gt;nMilliSecond;pInfo->pctrlProgress->SetPos(i);Sleep(nTemp); return 0;顺便补充一点,如果你在 void CMu ltiThread3Dlg:OnStart() 函数中 添加/* */ 语句,编译运行你就会发现进度条不进行刷新,主线程也停止 了反应。什么原因呢?这是因为 W aitForSing leObject 函数等待子线程 ( ThreadFunc )结束时,导致了线程死锁。因为 W aitForSingleObject函数会将主线程挂起(任何消息都得不到处理),而子线程 ThreadFunc 正 在设置进

28、度条,一直在等待主线程将刷新消息处理完毕返回才会检测通知 事件。这样两个线程都在互相等待,死锁发生了,编程时应注意避免。例程 4 Mu lt iThread4该例程测试在 W indows 下最多可创建线程的数目。1. 建立一个基于对话框的工程 Mu lt iThread4 ,在对话框IDD_MULT IT HREAD4_DIALOG 中加入一个按钮 IDC_TEST 和一个编辑框 IDC_COUNT ,按钮标题为“测试” , 编辑框属性选中 Read-only ;2. 在 Mu lt iThread4D lg.cpp 文件中进行如下操作:添加公共变量volatile BOOL m_bRunF

29、lag=TRUE;该变量表示是否还能继续创建线程。添加线程函数:DWORD WINAPI threadFunc(LPVOID threadNum)while(m_bRunFlag)Sleep(3000);return 0;只要 m_bRunFlag 变量为 TRUE ,线程一直运行。双击按钮 IDC_TEST ,添加其响应消息函数:void CMultiThread4Dlg:OnTest()DWORD threadID;GetDlgItem(IDC_TEST)->EnableWindow(FALSE);long nCount=0;while(m_bRunFlag)if(CreateThr

30、ead(NULL,0,threadFunc,NULL,0,&threadID)=NULL) m_bRunFlag=FALSE; break;elsenCount+;/ 不断创建线程, 直到再 不能创建 为止m_nCount=nCount;UpdateData(FALSE);Sleep(5000);/ 延时 5 秒,等待所有创建的线程结束GetDlgItem(IDC_TEST)->EnableWindow(TRUE); m_bRunFlag=TRUE;多线程编程之二一一MFC中的多线程开发作者:韩耀旭下载源代码五、MFC对多线程编程的支持MFC 中有两类线程 ,分别称之为工作者线程

31、和用户界面线程 。二者的 主要区 别在于工作者线 程没有消息循环,而用户界面线程有自己的消息队列和消息循 环。工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计 算过程,打印机的后台打印等。用户界面线程一般用于处理独立于其他线程执行 之外的用户输入,响应用户及系统所产生的事件和消息等。但对于Win32的API 编程而言,这两种线程是没有区别的,它们都只需线程的启动地址即可启动线程 来执行任务。在MFC中,一般用全局函数Afx Beg inThread() 来创建并初始化一个线程的 运行,该函数有两种重载形式,分别用于创建工作者线程和用户界面线程。两种 重载函数原型和参数分别说明

32、如下:(1) CWin Thread* AfxBegi nThread(AFX_THREADPROC pfnThreadProc,LPVOID pParam,n Priority=THREAD_PRIORITY_NORMAL, UINT n StackSize=O,DWORD dwCreateFlags=O, LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);PfnThreadProc:指向工作者线程的执行函数的指针,线程函数原型必须声明如下:UINT Execut in gFu nctio n(LPVOID pParam);请注意,Ex ecutingF

33、unction()应返回一个U INT类型的值,用以指明该函数结束的原因。一般情况下,返回0表明执行成功。pParam :传递给线程函数的一个32位参数,执行函数将用某种方式解释 该值。它可以是数值,或是指向一个结构的指针,甚至可以被忽略;* n Prior ity :线程的优先级。如果为0 ,则线程与其父线程具有相同的优先 级;« nStackSize:线程为自己分配堆栈的大小,其单位为字节。如果n StackSize 被设为0,则线程的堆栈被设置成与父线程堆栈相同大小;* dwCreateF lags :如果为0,则线程在创建后立刻开始执行。如果为CREATE_SUSPEND ,

34、则线程在创建后 立刻被挂起;* lpSecur ity Attrs :线程的安全属性指针,一般为NULL ;(2) CWin Thread* AfxBegi nThread(CR un timeClass* pThreadClass,intn Priority=THREAD_PRIORITY_NORMAL, UINT n StackSize=0,DWORD dwCreateFlags=0, LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL);pThreadClas s是指向 CW in Thread 的一个导出类的运行时类对象的指针, 该导出类定义了被创建的用

35、户界面线程的启动、退出等;其它参数的意义同形式1。使用函数的这个原型生成的线程也有消息机制,在以后的例子中我们将发现 同主线程的机制几乎一样。下面我们对CWinThread 类的数据成员及常用函数进行简要说明。 m_hThread :当前线程的句柄; m_nThreadlD:当前 线程的 ID ; m_pMainW nd :指向应用程序主窗口的指针BOOL CWin Thread:CreateThread(DWORD dwCreateFlags=O, UINT nStackSize=O,LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);该函 数中的 dwC

36、reateF lags、nStackSize 、lpSecur ity Attrs 参数和 API 函数 CreateThread 中的对应参数有相同含义,该函数执行成功,返回非0值,否则 返回0。一般情况下,调用Afx BeginThread() 来一次性地创建并启动一个线程,但是 也可以通过两步法来创建线程:首先创建CWinThread 类的一个对象,然后调用 该对象的成员函数CreateThread() 来启动该线程。virtual BOOL CWin Thread:I nit In sta nce();重载该函数以控制用户界面线程实例的初始化。初始化成功则返回非0值, 否则返回0。用户

37、界面线程经常重载该函数,工作者线程一般不使用In it Instance() 。virtual in t CWin Thread:Exit In sta nce();在线程终结前重载该函数进行一些必要的清理工作。该函数返回线程的退出 码,0表示执行成功,非0值用来标识各种错误。同In it Instance()成员函数一 样,该函数也只适用于用户界面线程。六、MFC多线程编程实例在Visual C+ 6.0 编程环 境中,我们既可以编写C风格的32位 W in32应 用程序,也可以利用MFC类库编写C+风格的应用程序,二者各有其优缺点。 基于Win32的应用程序执行代码小巧,运行效率高,但要求

38、程序员编写的代码 较多,且需要管理系统提供给程序的所有资源;而基于MFC类库的应用程序可 以快速建立起应用程序,类库为程序员提供了大量的封装类,而且Dev eloper Studio为程序员提供了一些工具来管理用户源程序,其缺点是类库代码很庞大。由于使用类库所带来的快速、简捷和功能强大等优越性,因此除非有特殊的需要, 否则 Visual C+ 推荐使用 MFC 类库进行程序开发。我们知道,MFC中的线程分为两种:用户界面线程和工作者线程。我们将分别举 例说明。用 MFC 类库编程实现工作者线程例程 5 Mu lt iThread5为了与 Win32 API 对照,我们使用 MFC 类库编程实现

39、例程 3 Mu lt iThread3 。1. 建立一个基于对话框的工程 Mult iThread5 ,在对话框IDD_MULT IT HREAD5_DIALOG 中加入一个编辑框 IDC_MILL ISECOND ,一 个按钮 IDC_START ,标题为“开始” ,一个进度条 IDC_PROGRESS1 ;2. 打开 ClassW izard ,为编辑框 IDC_MILL ISECOND 添加 int 型变量 m_nMilliSecond ,为进度条 IDC_PROGRESS1 添加 CProgressCtrl 型变量 m_ctrlProgress ;3. 在 Mu lt iThread5

40、D lg.h 文件中添加一个结构的定义:.;4. struct threadInfoUINT nMilliSecond;CProgressCtrl* pctrlProgress;线程函数的声明:UINT ThreadFunc(LPVOID lpParam);注意,二者应在类 CMult iThr ead5Dlg 的外部。在类 CMult iThr ead5Dlg 内部添加 protected 型变量:CWinThread* pThread;9. 在 Mu lt iThread5D lg.cpp 文件中进行如下操作:定义公共变量:threadInfo Info;双击按钮 IDC_S

41、TART ,添加相应消息处理函数:void CMultiThread5Dlg:OnStart()/ TODO: Add your control notification handler code hereUpdateData(TRUE); Info.nMilliSecond=m_nMilliSecond;Info.pctrlProgress=&m_ctrlProgress;pThread=AfxBeginThread(ThreadFunc, &Info);在 函 数 BOOL CMu lt iThread3Dlg:On In itDialog() 中 添 加 语 句 :/ T

42、ODO: Add extra initialization here m_ctrlProgress.SetRange(0,99); m_nMilliSecond=10;UpdateData(FALSE);toreturn TRUE; / return TRUE unless you set the focus a control添加线程处理函数:UINT ThreadFunc(LPVOID lpParam) threadInfo* pInfo=(threadInfo*)lpParam; for(int i=0;i<100;i+)int nTemp=pInfo->nMilliSeco

43、nd;pInfo->pctrlProgress->SetPos(i);Sleep(nTemp); return 0;用 MFC 类库编程实现 用户界面线程创建用户界面线程的步骤:1. 使 用 ClassW izard 创 建 类 CW inThread 的 派 生 类 ( 以 CUIThr ead 类 为 例 )2. class CUIThread : public CWinThread3. 4. DECLARE_DYNCREATE(CUIThread)5. protected:6. CUIThread();/ protected constructorused by dynami

44、c creation7.8./ Attributes9.public:10.11./ Operations12.public:13.14./ Overrides15./ ClassWizard generated virtual functionoverrides16./AFX_VIRTUAL(CUIThread)17.public:18.virtual BOOL InitInstance();19.virtual int ExitInstance();20./AFX_VIRTUAL21.22. / Implementation23. protected:24. virtual CUIThre

45、ad();25.26. / Generated message map functions27. /AFX_MSG(CUIThread)28. / NOTE- the ClassWizard will add and remove member functions here.29. /AFX_MSG30.31. DECLARE_MESSAGE_MAP()32. ;33. 重 载 函 数 In it Instance() 和 Ex it Instance() 。34. BOOL CUIThread:InitInstance()35. 36. CFrameWnd* wnd=new CFrameWn

46、d;37. wnd->Create(NULL,"UI Thread Window");38. wnd->ShowWindow(SW_SHOW);39. wnd->UpdateWindow();40. m_pMainWnd=wnd;41. return TRUE;42. 创建新的用户界面线程void CUIThreadDlg:OnButton1()CUIThread* pThread=new CUIThread();pThread->CreateThread();请注意以下两点:A 、 在 U IThreadDlg.cpp 的 开 头 加 入 语 句

47、:#include "UIThread.h"B 、 把 U IThread.h 中 类 CU IThread() 的 构 造 函 数 的 特 性 由 protected 改 为 public 。用户 界面线程 的执行 次序与 应用程 序主线程相同,首 先调用 用户界面 线 程 类 的 In it Instance() 函 数 ,如 果 返 回 TRUE ,继 续 调 用 线 程 的 Run() 函 数 ,该 函 数 的 作 用 是 运 行 一 个 标 准 的 消 息 循 环 ,并 且 当 收 到 W M_QUIT 消 息 后 中 断 ,在 消 息 循 环 过 程 中 ,Ru

48、n() 函 数 检 测 到 线 程 空 闲 时( 没 有 消 息 ), 也 将 调 用 OnId le() 函 数 , 最 后 Run() 函 数 返 回 , MFC 调 用 Ex it Instance() 函数清理资源。你可以创建一个没有界面而有消息循环的线程,例如:你可以从 CW inThread 派 生 一 个 新 类 , 在 In it Instance 函 数 中 完 成 某 项 任 务 并 返 回 FALSE , 这 表 示 仅 执 行 In it Instance 函 数 中 的 任 务 而 不 执 行 消 息 循 环 , 你 可以通过这种方法,完成一个工作者线程的功能。例程

49、6 Mu lt iThread61. 建立一个基于对话框的工程 Mu lt iThread6 ,在对话框 IDD_MULT IT HREAD6_DIALOG 中加入一个按钮 IDC_UI_T HREAD ,标题 为“用户界面线程”2. 右击工程并选中“ New Qas s”为工程添加基类为CW in Thread 派生线程 类 CUIThread 。3. 给工程添加新对话框 IDD_UITHREADDLG ,标题为“线程对话框”。4. 为对话框 IDD_UIT HREADDLG 创建一个基于 CDialog 的类 CUIThreadDlg 。 使用 ClassW izard 为 CUIThre

50、adD lg 类添加 WM_LBUTTONDOW N 消息的 处理函数 OnLButtonDown ,如下:5. void CUIThreadDlg:OnLButtonDown(UINT nFlags, CPoint point)6. 7. AfxMessageBox("You Clicked The Left Button!");8. CDialog:OnLButtonDown(nFlags, point);9. 在 UIThread.h 中添加#include "UIThreadDlg.h"并在 CUIThread 类中添加 protected 变量

51、 CUIThread m_dlg :class CUIThread : public CWinThreadDECLARE_DYNCREATE(CUIThread)protected:CUIThread();/ protected constructor used bydynamic creation/ Attributespublic:/ Operationspublic:/ Overrides/ ClassWizard generated virtual function overrides/AFX_VIRTUAL(CUIThread)public:virtual BOOL InitInst

52、ance();virtual int ExitInstance(); /AFX_VIRTUAL/ Implementationprotected:CUIThreadDlg m_dlg;virtual CUIThread();/ Generated message map functions /AFX_MSG(CUIThread)/ NOTE- the ClassWizard will add and remove member functions here./AFX_MSGDECLARE_MESSAGE_MAP();10. 分 别 重 载 In it Instance() 函 数 和 Ex i

53、t Instance() 函 数 :11. BOOL CUIThread:InitInstance()12. 13. m_dlg.Create(IDD_UITHREADDLG);14. m_dlg.ShowWindow(SW_SHOW);15. m_pMainWnd=&m_dlg;16. return TRUE;17. 18.19. int CUIThread:ExitInstance()20. 21. m_dlg.DestroyWindow();22. return CWinThread:ExitInstance();23. 24. 双击按钮 IDC_UI_T HREAD ,添加消息

54、响应函数:25. void CMultiThread6Dlg:OnUiThread()26. 27.CWinThread*pThread=AfxBeginThread(RUNTIME_CLASS(CUIThread);28. 并 在 Mu lt iThread6D lg.cpp 的 开 头 添 加 :#include "UIThread.h"好了,编译并运行程序吧。每 单击一次“用户界面线程”按钮,都会弹出一个 线程对话框,在任何一个线程对话框内按下鼠标左键,都会弹出一个消息框。多线程编程之三线 程间通讯作者:韩耀旭下载源代码七、线程间通讯一般而言,应用程序中的一个次要线程

55、总是为主线程执行特定的任务,这样, 主线程和次要线程间必定有一个信息传递的渠道,也就是主线程和次要线程间要 进行通信。这种线程间的通 信不但是难以避免的,而且在多线程编程中也是复杂 和频繁的,下面将进行说明。1. 使 用全局 变量进行 通信由 于 属 于 同 一 个 进 程 的 各 个 线 程 共 享 操 作 系 统 分 配 该 进 程 的 资 源 ,故 解 决 线程间通信最简单的一种方法是使用全局变量。对于标准类型的全局变 量 ,我 们 建 议 使 用 volat ile 修 饰 符 ,它 告 诉 编 译 器 无 需 对 该 变 量 作 任 何 的 优 化 ,即 无 需 将 它 放 到 一

56、个 寄 存 器 中 ,并 且 该 值 可 被 外 部 改 变 。如 果 线 程 间 所 需 传 递 的 信 息 较 复 杂 ,我 们 可 以 定 义 一 个 结 构 ,通 过 传 递 指 向 该 结 构 的指针进行传递信息。2. 使 用自定 义消息我们可以在一个线程的执行函数中向另一个线程发送自定义的消息来达 到通信的目的。一个线程向另外一个线程发送消息是通过操作系统实现 的 。 利 用 W indows 操 作 系 统 的 消 息 驱 动 机 制 , 当 一 个 线 程 发 出 一 条 消 息 时 ,操 作 系 统 首 先 接 收 到 该 消 息 ,然 后 把 该 消 息 转 发 给 目 标 线 程 ,接 收 消 息的线程必须已经建立了消息循环。例 程 7 Mu lt iThread7该例程演示了如何使用自定义消息进行线程间通信。首先,主线程向CCalcula

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论