多线程之间的通信

上传人:ji****72 文档编号:37683100 上传时间:2018-04-20 格式:DOC 页数:15 大小:57KB
返回 下载 相关 举报
多线程之间的通信_第1页
第1页 / 共15页
多线程之间的通信_第2页
第2页 / 共15页
多线程之间的通信_第3页
第3页 / 共15页
多线程之间的通信_第4页
第4页 / 共15页
多线程之间的通信_第5页
第5页 / 共15页
点击查看更多>>
资源描述

《多线程之间的通信》由会员分享,可在线阅读,更多相关《多线程之间的通信(15页珍藏版)》请在金锄头文库上搜索。

1、当前流行的 Windows 操作系统能同时运行几个程序(独立运行的程序又称之为进程),对于 同一个程序,它又可以分成若干个独立的执行流,我们称之为线程,线程提供了多任务处 理的能力。用进程和线程的观点来研究软件是当今普遍采用的方法,进程和线程的概念的 出现,对提高软件的并行性有着重要的意义。现在的大型应用软件无一不是多线程多任务 处理,单线程的软件是不可想象的。因此掌握多线程多任务设计方法对每个程序员都是必 需要掌握的。本实例针对多线程技术在应用中经常遇到的问题,如线程间的通信、同步等, 分别进行探讨,并利用多线程技术进行线程之间的通信,实现了数字的简单排序。 一、 实现方法1、理解线程要讲解

2、线程,不得不说一下进程,进程是应用程序的执行实例,每个进程是由私有的 虚拟地址空间、代码、数据和其它系统资源组成。进程在运行时创建的资源随着进程的终 止而死亡。线程的基本思想很简单,它是一个独立的执行流,是进程内部的一个独立的执 行单元,相当于一个子程序,它对应于 Visual C+中的 CwinThread 类对象。单独一个执行 程序运行时,缺省地包含的一个主线程,主线程以函数地址的形式出现,提供程序的启动 点,如 main()或 WinMain()函数等。当主线程终止时,进程也随之终止。根据实际需 要,应用程序可以分解成许多独立执行的线程,每个线程并行的运行在同一进程中。一个进程中的所有线

3、程都在该进程的虚拟地址空间中,使用该进程的全局变量和系统 资源。操作系统给每个线程分配不同的 CPU 时间片,在某一个时刻,CPU 只执行一个时 间片内的线程,多个时间片中的相应线程在 CPU 内轮流执行,由于每个时间片时间很短, 所以对用户来说,仿佛各个线程在计算机中是并行处理的。操作系统是根据线程的优先级 来安排 CPU 的时间,优先级高的线程优先运行,优先级低的线程则继续等待。线程被分为两种:用户界面线程和工作线程(又称为后台线程) 。用户界面线程通常用 来处理用户的输入并响应各种事件和消息,其实,应用程序的主执行线程 CWinAPP 对象 就是一个用户界面线程,当应用程序启动时自动创建

4、和启动,同样它的终止也意味着该程 序的结束,进程终止。工作线程用来执行程序的后台处理任务,比如计算、调度、对串口 的读写操作等,它和用户界面线程的区别是它不用从 CWinThread 类派生来创建,对它来 说最重要的是如何实现工作线程任务的运行控制函数。工作线程和用户界面线程启动时要 调用同一个函数的不同版本;最后需要读者明白的是,一个进程中的所有线程共享它们父 进程的变量,但同时每个线程可以拥有自己的变量。 2、线程的管理和操作(一)线程的启动创建一个用户界面线程,首先要从类 CwinThread 产生一个派生类,同时必须使用 DECLARE_DYNCREATE 和 IMPLEMENT_DY

5、NCREATE 来声明和实现这个 CwinThread 派生类。第二步是根据需要重载该派生类的一些成员函数如:ExitInstance() 、 InitInstance() 、OnIdle() 、PreTranslateMessage()等函数。最后调用 AfxBeginThread() 函数的一个版本:CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSE

6、CURITY_ATTRIBUTES lpSecurityAttrs = NULL ) 启动该用户界面线程,其中第一个 参数为指向定义的用户界面线程类指针变量,第二个参数为线程的优先级,第三个参数为 线程所对应的堆栈大小,第四个参数为线程创建时的附加标志,缺省为正常状态,如为 CREATE_SUSPENDED 则线程启动后为挂起状态。对于工作线程来说,启动一个线程,首先需要编写一个希望与应用程序的其余部分并 行运行的函数如 Fun1(),接着定义一个指向 CwinThread 对象的指针变量*pThread,调用 AfxBeginThread(Fun1,param,priority)函数,返回值

7、赋给 pThread 变量的同时一并启动该线程 来执行上面的 Fun1()函数,其中 Fun1 是线程要运行的函数的名字,也既是上面所说的 控制函数的名字,param 是准备传送给线程函数 Fun1 的任意 32 位值,priority 则是定义该 线程的优先级别,它是预定义的常数,读者可参考 MSDN。(二)线程的优先级以下的 CwinThread 类的成员函数用于线程优先级的操作:int GetThreadPriority() ; BOOL SetThradPriority()(int nPriority);上述的二个函数分别用来获取和设置线程的优先级,这里的优先级,是相对于该线程 所处的

8、优先权层次而言的,处于同一优先权层次的线程,优先级高的线程先运行;处于不 同优先权层次上的线程,谁的优先权层次高,谁先运行。至于优先级设置所需的常数,自 己参考 MSDN 就可以了,要注意的是要想设置线程的优先级,这个线程在创建时必须具有 THREAD_SET_INFORMATION 访问权限。对于线程的优先权层次的设置,CwinThread 类 没有提供相应的函数,但是可以通过 Win32 SDK 函数 GetPriorityClass()和 SetPriorityClass()来实现。(三)线程的悬挂和恢复CWinThread 类中包含了应用程序悬挂和恢复它所创建的线程的函数,其中 Sus

9、pendThread()用来悬挂线程,暂停线程的执行;ResumeThread()用来恢复线程的执 行。如果你对一个线程连续若干次执行 SuspendThread() ,则需要连续执行相应次的 ResumeThread()来恢复线程的运行。(四)结束线程终止线程有三种途径,线程可以在自身内部调用 AfxEndThread()来终止自身的运行; 可以在线程的外部调用 BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode )来 强行终止一个线程的运行,然后调用 CloseHandle()函数释放线程所占用的堆栈;第三种 方法是改变全局变量,使

10、线程的执行函数返回,则该线程终止。下面以第三种方法为例, 给出部分代码:/ /CtestView message handlers/Set to True to end thread Bool bend=FALSE;/定义的全局变量,用于控制线程的运行; /The Thread Function; UINT ThreadFunction(LPVOID pParam)/线程函数 while(!bend)Beep(100,100);Sleep(1000);return 0; / CwinThread *pThread; HWND hWnd; Void CtestView:OninitialUpda

11、te() hWnd=GetSafeHwnd();pThread=AfxBeginThread(ThradFunction,hWnd);/启动线程pThread-m_bAutoDelete=FALSE;/线程为手动删除Cview:OnInitialUpdate(); / Void CtestView:OnDestroy() bend=TRUE;/改变变量,线程结束WaitForSingleObject(pThread-m_hThread,INFINITE);/等待线程结束delete pThread;/删除线程Cview:OnDestroy(); 3、线程之间的通信通常情况下,一个次级线程要为主

12、线程完成某种特定类型的任务,这就隐含着表示在 主线程和次级线程之间需要建立一个通信的通道。一般情况下,有下面的几种方法实现这 种通信任务:使用全局变量(上一节的例子其实使用的就是这种方法) 、使用事件对象、使 用消息。这里我们主要介绍后两种方法。(一) 利用用户定义的消息通信在 Windows 程序设计中,应用程序的每一个线程都拥有自己的消息队列,甚至工作线 程也不例外,这样一来,就使得线程之间利用消息来传递信息就变的非常简单。首先用户 要定义一个用户消息,如下所示:#define WM_USERMSG WMUSER+100;在需要的时候, 在一个线程中调用:PostMessage(HWND)

13、param,WM_USERMSG,0,0)或 CwinThread:PostThradMessage()来向另外一个线程发送这个消息,上述函数的四个参数分别是消息将要发送到的目的窗口的句柄、要发送的消息标志符、消息的参数 WPARAM 和 LPARAM。下面的代码是对上节代码的修改,修改后的结果是在线程结束时显示一个对 话框,提示线程结束:UINT ThreadFunction(LPVOID pParam) while(!bend)Beep(100,100);Sleep(1000);:PostMessage(hWnd,WM_USERMSG,0,0);return 0; /WM_USERMSG

14、消息的响应函数为 OnThreadended(WPARAM wParam, LPARAM lParam) LONG CTestView:OnThreadended(WPARAM wParam,LPARAM lParam) AfxMessageBox(“Thread ended.“);Retrun 0; 上面的例子是工作者线程向用户界面线程发送消息,对于工作者线程,如果它的设计 模式也是消息驱动的,那么调用者可以向它发送初始化、退出、执行某种特定的处理等消 息,让它在后台完成。在控制函数中可以直接使用:GetMessage()这个 SDK 函数进行消 息分检和处理,自己实现一个消息循环。GetM

15、essage()函数在判断该线程的消息队列为空 时,线程将系统分配给它的时间片让给其它线程,不无效的占用 CPU 的时间,如果消息队 列不为空,就获取这个消息,判断这个消息的内容并进行相应的处理。(二)用事件对象实现通信在线程之间传递信号进行通信比较复杂的方法是使用事件对象,用 MFC 的 Cevent 类 的对象来表示。事件对象处于两种状态之一:有信号和无信号,线程可以监视处于有信号 状态的事件,以便在适当的时候执行对事件的操作。上述例子代码修改如下: / Cevent threadStart ,threadEnd; UINT ThreadFunction(LPVOID pParam) :WaitForSingleObject(threadStart.m_hObject,INFINITE);AfxMessageBox(“Thread start.“);while(!bend)Beep(100,100);Sleep(1000);Int result=:WaitforSingleObject(threadEnd.m_hObject,0);/等待 thre

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号