线程.docx

上传人:b****4 文档编号:26889446 上传时间:2023-06-23 格式:DOCX 页数:25 大小:84.01KB
下载 相关 举报
线程.docx_第1页
第1页 / 共25页
线程.docx_第2页
第2页 / 共25页
线程.docx_第3页
第3页 / 共25页
线程.docx_第4页
第4页 / 共25页
线程.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

线程.docx

《线程.docx》由会员分享,可在线阅读,更多相关《线程.docx(25页珍藏版)》请在冰豆网上搜索。

线程.docx

线程

1、创建和终止线程

  在MFC程序中创建一个线程,宜调用AfxBeginThread函数。

该函数因参数不同而具有两种重载版本,分别对应工作者线程和用户接口(UI)线程。

  工作者线程

CWinThread*AfxBeginThread(

 AFX_THREADPROCpfnThreadProc,//控制函数

 LPVOIDpParam,//传递给控制函数的参数

 intnPriority=THREAD_PRIORITY_NORMAL,//线程的优先级

 UINTnStackSize=0,//线程的堆栈大小

 DWORDdwCreateFlags=0,//线程的创建标志

 LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL//线程的安全属性

);

  工作者线程编程较为简单,只需编写线程控制函数和启动线程即可。

下面的代码给出了定义一个控制函数和启动它的过程:

//线程控制函数

UINTMfcThreadProc(LPVOIDlpParam)

{

 CExampleClass*lpObject=(CExampleClass*)lpParam;

 if(lpObject==NULL||!

lpObject->IsKindof(RUNTIME_CLASS(CExampleClass)))

  return-1;//输入参数非法

 //线程成功启动

 while

(1)

 

 return0;

}

//在MFC程序中启动线程

AfxBeginThread(MfcThreadProc,lpObject);

  UI线程

  创建用户界面线程时,必须首先从CWinThread派生类,并使用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE宏声明此类。

  下面给出了CWinThread类的原型(添加了关于其重要函数功能和是否需要被继承类重载的注释):

classCWinThread:

publicCCmdTarget

{

 DECLARE_DYNAMIC(CWinThread)

 public:

  //Constructors

  CWinThread();

  BOOLCreateThread(DWORDdwCreateFlags=0,UINTnStackSize=0,

LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL);

  //Attributes

  CWnd*m_pMainWnd;//mainwindow(usuallysameAfxGetApp()->m_pMainWnd)

  CWnd*m_pActiveWnd;//activemainwindow(maynotbem_pMainWnd)

  BOOLm_bAutoDelete;//enables'deletethis'afterthreadtermination

  //onlyvalidwhilerunning

  HANDLEm_hThread;//thisthread'sHANDLE

  operatorHANDLE()const;

  DWORDm_nThreadID;//thisthread'sID

  intGetThreadPriority();

  BOOLSetThreadPriority(intnPriority);

  //Operations

  DWORDSuspendThread();

  DWORDResumeThread();

  BOOLPostThreadMessage(UINTmessage,WPARAMwParam,LPARAMlParam);

  //Overridables

  //执行线程实例初始化,必须重写

  virtualBOOLInitInstance();

  //runningandidleprocessing

  //控制线程的函数,包含消息泵,一般不重写

  virtualintRun();

  //消息调度到TranslateMessage和DispatchMessage之前对其进行筛选,

  //通常不重写

  virtualBOOLPreTranslateMessage(MSG*pMsg);

  virtualBOOLPumpMessage();//lowlevelmessagepump

  //执行线程特定的闲置时间处理,通常不重写

  virtualBOOLOnIdle(LONGlCount);//returnTRUEifmoreidleprocessing

  virtualBOOLIsIdleMessage(MSG*pMsg);//checksforspecialmessages

  //线程终止时执行清除,通常需要重写

  virtualintExitInstance();//defaultwill'deletethis'

  //截获由线程的消息和命令处理程序引发的未处理异常,通常不重写

  virtualLRESULTProcessWndProcException(CException*e,constMSG*pMsg);

  //Advanced:

handlingmessagessenttomessagefilterhook

  virtualBOOLProcessMessageFilter(intcode,LPMSGlpMsg);

  //Advanced:

virtualaccesstom_pMainWnd

  virtualCWnd*GetMainWnd();

  //Implementation

 public:

  virtual~CWinThread();

  #ifdef_DEBUG

   virtualvoidAssertValid()const;

   virtualvoidDump(CDumpContext&dc)const;

   intm_nDisablePumpCount;//Diagnostictraptodetectillegalre-entrancy

  #endif

  voidCommonConstruct();

  virtualvoidDelete();

  //'deletethis'onlyifm_bAutoDelete==TRUE

  //messagepumpforRun

  MSGm_msgCur;//currentmessage

 public:

  //constructorusedbyimplementationofAfxBeginThread

  CWinThread(AFX_THREADPROCpfnThreadProc,LPVOIDpParam);

  //validafterconstruction

  LPVOIDm_pThreadParams;//genericparameterspassedtostartingfunction

  AFX_THREADPROCm_pfnThreadProc;

  //setafterOLEisinitialized

  void(AFXAPI*m_lpfnOleTermOrFreeLib)(BOOL,BOOL);

  COleMessageFilter*m_pMessageFilter;

 protected:

  CPointm_ptCursorLast;//lastmouseposition

  UINTm_nMsgLast;//lastmousemessage

  BOOLDispatchThreadMessageEx(MSG*msg);//helper

  voidDispatchThreadMessage(MSG*msg);//obsolete

};

  启动UI线程的AfxBeginThread函数的原型为:

CWinThread*AfxBeginThread(

 //从CWinThread派生的类的RUNTIME_CLASS

 CRuntimeClass*pThreadClass,

 intnPriority=THREAD_PRIORITY_NORMAL,

 UINTnStackSize=0,

 DWORDdwCreateFlags=0,

 LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL

);

  我们可以方便地使用VC++6.0类向导定义一个继承自CWinThread的用户线程类。

下面给出产生我们自定义的CWinThread子类CMyUIThread的方法。

  打开VC++6.0类向导,在如下窗口中选择BaseClass类为CWinThread,输入子类名为CMyUIThread,点击"OK"按钮后就产生了类CMyUIThread。

  其源代码框架为:

/////////////////////////////////////////////////////////////////////////////

//CMyUIThreadthread

classCMyUIThread:

publicCWinThread

{

 DECLARE_DYNCREATE(CMyUIThread)

 protected:

  CMyUIThread();//protectedconstructorusedbydynamiccreation

  //Attributes

 public:

  //Operations

 public:

  //Overrides

  //ClassWizardgeneratedvirtualfunctionoverrides

  //{{AFX_VIRTUAL(CMyUIThread)

  public:

   virtualBOOLInitInstance();

   virtualintExitInstance();

  //}}AFX_VIRTUAL

  //Implementation

 protected:

  virtual~CMyUIThread();

  //Generatedmessagemapfunctions

  //{{AFX_MSG(CMyUIThread)

   //NOTE-theClassWizardwilladdandremovememberfunctionshere.

  //}}AFX_MSG

 DECLARE_MESSAGE_MAP()

};

/////////////////////////////////////////////////////////////////////////////

//CMyUIThread

IMPLEMENT_DYNCREATE(CMyUIThread,CWinThread)

CMyUIThread:

:

CMyUIThread()

{}

CMyUIThread:

:

~CMyUIThread()

{}

BOOLCMyUIThread:

:

InitInstance()

{

 //TODO:

performandper-threadinitializationhere

 returnTRUE;

}

intCMyUIThread:

:

ExitInstance()

{

 //TODO:

performanyper-threadcleanuphere

 returnCWinThread:

:

ExitInstance();

}

BEGIN_MESSAGE_MAP(CMyUIThread,CWinThread)

//{{AFX_MSG_MAP(CMyUIThread)

//NOTE-theClassWizardwilladdandremovemappingmacroshere.

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

  使用下列代码就可以启动这个UI线程:

CMyUIThread*pThread;

pThread=(CMyUIThread*)

AfxBeginThread(RUNTIME_CLASS(CMyUIThread));

  另外,我们也可以不用AfxBeginThread创建线程,而是分如下两步完成:

  

(1)调用线程类的构造函数创建一个线程对象;

  

(2)调用CWinThread:

:

CreateThread函数来启动该线程。

  在线程自身内调用AfxEndThread函数可以终止该线程:

voidAfxEndThread(

 UINTnExitCode//theexitcodeofthethread

);

  对于UI线程而言,如果消息队列中放入了WM_QUIT消息,将结束线程。

  关于UI线程和工作者线程的分配,最好的做法是:

将所有与UI相关的操作放入主线程,其它的纯粹的运算工作交给独立的数个工作者线程。

  候捷先生早些时间喜欢为MDI程序的每个窗口创建一个线程,他后来澄清了这个错误。

因为如果为MDI程序的每个窗口都单独创建一个线程,在窗口进行切换的时候,将进行线程的上下文切换!

2.线程间通信

  MFC中定义了继承自CSyncObject类的CCriticalSection、CCEvent、CMutex、CSemaphore类封装和简化了WIN32API所提供的临界区、事件、互斥和信号量。

使用这些同步机制,必须包含"Afxmt.h"头文件。

下图给出了类的继承关系:

  作为CSyncObject类的继承类,我们仅仅使用基类CSyncObject的接口函数就可以方便、统一的操作CCriticalSection、CCEvent、CMutex、CSemaphore类,下面是CSyncObject类的原型:

classCSyncObject:

publicCObject

{

 DECLARE_DYNAMIC(CSyncObject)

 //Constructor

 public:

  CSyncObject(LPCTSTRpstrName);

  //Attributes

 public:

  operatorHANDLE()const;

  HANDLEm_hObject;

  //Operations

  virtualBOOLLock(DWORDdwTimeout=INFINITE);

  virtualBOOLUnlock()=0;

  virtualBOOLUnlock(LONG/*lCount*/,LPLONG/*lpPrevCount="NULL"*/)

  {returnTRUE;}

  //Implementation

 public:

  virtual~CSyncObject();

  #ifdef_DEBUG

   CStringm_strName;

   virtualvoidAssertValid()const;

   virtualvoidDump(CDumpContext&dc)const;

  #endif

  friendclassCSingleLock;

  friendclassCMultiLock;

};

  CSyncObject类最主要的两个函数是Lock和Unlock,若我们直接使用CSyncObject类及其派生类,我们需要非常小心地在Lock之后调用Unlock。

  MFC提供的另两个类CSingleLock(等待一个对象)和CMultiLock(等待多个对象)为我们编写应用程序提供了更灵活的机制,下面以实际来阐述CSingleLock的用法:

classCThreadSafeWnd

  ~CThreadSafeWnd(){}

  voidSetWindow(CWnd*pwnd)

  {

   m_pCWnd=pwnd;

  }

  voidPaintBall(COLORREFcolor,CRect&rc);

 private:

  CWnd*m_pCWnd;

  CCriticalSectionm_CSect;

};

voidCThreadSafeWnd:

:

PaintBall(COLORREFcolor,CRect&rc)

{

 CSingleLockcsl(&m_CSect);

 //缺省的Timeout是INFINITE,只有m_Csect被激活,csl.Lock()才能返回

 //true,这里一直等待

 if(csl.Lock())

;

 {

  //notnecessary

  //AFX_MANAGE_STATE(AfxGetStaticModuleState());

  CDC*pdc=m_pCWnd->GetDC();

  CBrushbrush(color);

  CBrush*oldbrush=pdc->SelectObject(&brush);

  pdc->Ellipse(rc);

  pdc->SelectObject(oldbrush);

  GdiFlush();//don'twaittoupdatethedisplay

 }

}

  上述实例讲述了用CSingleLock对WindowsGDI相关对象进行保护的方法,下面再给出一个其他方面的例子:

intarray1[10],array2[10];

CMutexSectionsection;//创建一个CMutex类的对象

//赋值线程控制函数

UINTEvaluateThread(LPVOIDparam)

{

 CSingleLocksinglelock;

 singlelock(§ion);

 //互斥区域

 singlelock.Lock();

 for(inti=0;i<10;i++)

  array1[i]=i;

 singlelock.Unlock();

}

//拷贝线程控制函数

UINTCopyThread(LPVOIDparam)

{

 CSingleLocksinglelock;

 singlelock(§ion);

 //互斥区域

 singlelock.Lock();

 for(inti=0;i<10;i++)

  array2[i]=array1[i];

 singlelock.Unlock();

}

}

AfxBeginThread(EvaluateThread,NULL);//启动赋值线程

AfxBeginThread(CopyThread,NULL);//启动拷贝线程

  上面的例子中启动了两个线程EvaluateThread和CopyThread,线程EvaluateThread把10个数赋值给数组array1[],线程CopyThread将数组array1[]拷贝给数组array2[]。

由于数组的拷贝和赋值都是整体行为,如果不以互斥形式执行代码段:

for(inti=0;i<10;i++)

array1[i]=i;

  和

for(inti=0;i<10;i++)

array2[i]=array1[i];

  其结果是很难预料的!

  除了可使用CCriticalSection、CEvent、CMutex、CSemaphore作为线程间同步通信的方式以外,我们还可以利用PostThreadMessage函数在线程间发送消息:

BOOLPostThreadMessage(DWORDidThread,//threadidentifier

UINTMsg,//messagetopost

WPARAMwParam,//firstmessageparameter

LPARAMlParam//secondmessageparameter

 

3.线程与消息队列

  在WIN32中,每一个线程都对应着一个消息队列。

由于一个线程可以产生数个窗口,所以并不是每个窗口都对应着一个消息队列。

下列几句话应该作为"定理"被记住:

  "定理"一

  所有产生给某个窗口的消息,都先由创建这个窗口的线程处理;

  "定理"二

  Windows屏幕上的每一个控件都是一个窗口,有对应的窗口函数。

  消息的发送通常有两种方式,一是SendMessage,一是PostMessage,其原型分别为:

LRESULTSendMessage(HWNDhWnd,//handleofdestinationwindow

 UINTMsg,//messagetosend

 WPARAMwParam,//firstmessageparameter

 LPARAMlParam//secondmessageparameter

);

BOOLPostMessage(HWNDhWnd,//handleofdestinationwindow

 UINTMsg,//messagetopost

 WPARAMwParam,//firstmessageparameter

 LPARAMlParam//secondmessageparameter

);

  两个函数原型中的四个参数的意义相同,但是SendMessage和PostMessage的行为有差异。

SendMessage必须等待消息被处理后才返回,而PostMessage仅仅将消息放入消息队列。

SendMessage的目标窗口如果属于另一个线程,则会发生线程上下文切换,等待另一线程处理完成消息。

为了防止另一线程当掉,导致SendMessage永远不能返回,我们可以调用SendMessageTimeout函数:

LRESULTSendMessageTimeo

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 考试认证 > 司法考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1