??xml version="1.0" encoding="utf-8" standalone="yes"?>久久99精品久久久大学生,国内精品综合久久久40p,精品久久无码中文字幕http://www.shnenglu.com/bhjjkg/See gullzh-cnWed, 07 May 2025 17:30:18 GMTWed, 07 May 2025 17:30:18 GMT60L"发帖水王" http://www.shnenglu.com/bhjjkg/archive/2009/07/09/89581.htmlWood_KWood_KWed, 08 Jul 2009 19:10:00 GMThttp://www.shnenglu.com/bhjjkg/archive/2009/07/09/89581.htmlhttp://www.shnenglu.com/bhjjkg/comments/89581.htmlhttp://www.shnenglu.com/bhjjkg/archive/2009/07/09/89581.html#Feedback5http://www.shnenglu.com/bhjjkg/comments/commentRss/89581.htmlhttp://www.shnenglu.com/bhjjkg/services/trackbacks/89581.html

一个论坛中又一?#8220;水王”Q他不但喜欢发帖Q还会回复其他ID发的每个帖子。该“水王”发帖数目过了L的一半。如果你又一个当前论坛所有帖子(包括回帖Q的列表Q其中帖子作者的ID也在表中Q你能快速找个传说中的水王吗Q?/p>

 

分析与解法:

  首先惛_的是一个最直接的方法,我们可以队所有IDq行排序。然后再扫描一遍排好序的ID列表Q统计各个ID出现的次数。如果某个ID出现的次数超qL的一半,那么p个ID。这个算法的旉复杂度ؓO(N*log2N+N)?/p>

 

如果一个ID出现的次数超qLN的一半。那么,无论水王的ID是什么,q个有序的ID列表中的WN/2(?开始编P一定会是这个IDQ读者可以试着证明一下)。省去重新扫描一遍列表,可以节省一点算法耗费的时间。如果能够迅速定位到列表的某一(比如使用数组来存储列表)Q除L序的旉复杂度,后处理需要的旉为OQ?Q?/p>

如果每次删除两个不同的IDQ不是否包?#8220;水王”的IDQ,那么Q在剩下的ID列表中,“水王”ID出现的次C然超qL的一半。看到这一点之后,可以通过不断重复q个q程Q把ID列表中的IDL降低Q{化ؓ更小的问题)Q从而得到问题的{案。新的思\Q避免了排序q个耗时的步骤,ȝ旉复杂度只有OQNQ,且只需要常数的额外内存?/p>

Wood_K 2009-07-09 03:10 发表评论
]]>
初识VC多线E编E?/title><link>http://www.shnenglu.com/bhjjkg/archive/2009/07/03/89132.html</link><dc:creator>Wood_K</dc:creator><author>Wood_K</author><pubDate>Thu, 02 Jul 2009 23:56:00 GMT</pubDate><guid>http://www.shnenglu.com/bhjjkg/archive/2009/07/03/89132.html</guid><wfw:comment>http://www.shnenglu.com/bhjjkg/comments/89132.html</wfw:comment><comments>http://www.shnenglu.com/bhjjkg/archive/2009/07/03/89132.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/bhjjkg/comments/commentRss/89132.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/bhjjkg/services/trackbacks/89132.html</trackback:ping><description><![CDATA[<p><br>VC中多U程使用比较q泛而且实用,在网上看到的教程.感觉写的挺好. </p> <p>一、问题的提出</p> <p>~写一个耗时的单U程E序Q?/p> <p>  新徏一个基于对话框的应用程序SingleThreadQ在d话框IDD_SINGLETHREAD_DIALOGd一个按钮,ID为IDC_SLEEP_SIX_SECONDQ标题ؓ“延时6U?#8221;Q添加按钮的响应函数Q代码如下: </p> <p>void CSingleThreadDlg::OnSleepSixSecond() <br>{<br> Sleep(6000); //延时6U?br>}</p> <p>  ~译q运行应用程序,单击“延时6U?#8221;按钮Q你׃发现在这6U期间程序就?#8220;L”一P不在响应其它消息。ؓ了更好地处理q种耗时的操作,我们有必要学习——多U程~程?br>二、多U程概述</p> <p>  q程和线E都是操作系l的概念。进E是应用E序的执行实例,每个q程是由U有的虚拟地址I间、代码、数据和其它各种pȝ资源l成Q进E在q行q程中创建的资源随着q程的终止而被销毁,所使用的系l资源在q程l止时被释放或关闭?br>  U程是进E内部的一个执行单元。系l创建好q程后,实际上就启动执行了该q程的主执行U程Q主执行U程以函数地址形式Q比如说main或WinMain函数Q将E序的启动点提供lWindowspȝ。主执行U程l止了,q程也就随之l止?br>  每一个进E至有一个主执行U程Q它无需q户去d创徏Q是ql自动创建的。用h据需要在应用E序中创建其它线E,多个U程q发地运行于同一个进E中。一个进E中的所有线E都在该q程的虚拟地址I间中,共同使用q些虚拟地址I间、全局变量和系l资源,所以线E间的通讯非常方便Q多U程技术的应用也较为广泛?br>  多线E可以实现ƈ行处理,避免了某Q务长旉占用CPU旉。要说明的一Ҏ(gu)Q目前大多数的计机都是单处理器QCPUQ的Qؓ了运行所有这些线E,操作pȝ为每个独立线E安排一些CPU旉Q操作系l以轮换方式向线E提供时间片Q这qZU假象,好象q些U程都在同时q行。由此可见,如果两个非常z跃的线Eؓ了抢夺对CPU的控制权Q在U程切换时会消耗很多的CPU资源Q反而会降低pȝ的性能。这一点在多线E编E时应该注意?br>  Win32 SDK函数支持q行多线E的E序设计Qƈ提供了操作系l原理中的各U同步、互斥和临界区等操作。Visual C++ 6.0中,使用MFCcd也实C多线E的E序设计Q得多U程~程更加方便?/p> <p>三、Win32 API对多U程~程的支?/p> <p>  Win32 提供了一pd的API函数来完成线E的创徏、挂赗恢复、终l以及通信{工作。下面将选取其中的一些重要函数进行说明?</p> <p>1、HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,<br>                 DWORD dwStackSize,<br>                 LPTHREAD_START_ROUTINE lpStartAddress,<br>                 LPVOID lpParameter,<br>                 DWORD dwCreationFlags,<br>                 LPDWORD lpThreadId);</p> <p>该函数在其调用进E的q程I间里创Z个新的线E,q返回已建线E的句柄Q其中各参数说明如下Q?br>lpThreadAttributesQ指向一?SECURITY_ATTRIBUTES l构的指针,该结构决定了U程的安全属性,一般置?NULLQ?<br>dwStackSizeQ指定了U程的堆栈深度,一般都讄?Q?<br>lpStartAddressQ表C新U程开始执行时代码所在函数的地址Q即U程的v始地址。一般情况ؓ(LPTHREAD_START_ROUTINE)ThreadFuncQThreadFunc 是线E函数名Q?<br>lpParameterQ指定了U程执行时传送给U程?2位参敎ͼ即线E函数的参数Q?<br>dwCreationFlagsQ控制线E创建的附加标志Q可以取两种倹{如果该参数?Q线E在被创建后׃立即开始执行;如果该参CؓCREATE_SUSPENDED,则系l生线E后Q该U程处于挂v状态,q不马上执行Q直臛_数ResumeThread被调用; <br>lpThreadIdQ该参数q回所创徏U程的IDQ?<br>如果创徏成功则返回线E的句柄Q否则返回NULL?</p> <p>2、DWORD SuspendThread(HANDLE hThread);</p> <p>该函数用于挂h定的U程Q如果函数执行成功,则线E的执行被终止?3、DWORD ResumeThread(HANDLE hThread);</p> <p>该函数用于结束线E的挂v状态,执行U程?4、VOID ExitThread(DWORD dwExitCode);</p> <p>该函数用于线E终l自w的执行Q主要在U程的执行函C被调用。其中参数dwExitCode用来讄U程的退出码?5、BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);</p> <p>  一般情况下Q线E运行结束之后,U程函数正常q回Q但是应用程序可以调用TerminateThreadl止某一U程的执行。各参数含义如下Q?br>hThreadQ将被终l的U程的句柄; <br>dwExitCodeQ用于指定线E的退出码?<br>  使用TerminateThread()l止某个U程的执行是不安全的Q可能会引vpȝ不稳定;虽然该函数立即终止线E的执行Q但q不释放U程所占用的资源。因此,一般不使用该函数?</p> <p>6、BOOL PostThreadMessage(DWORD idThread,<br>   UINT Msg,<br>   WPARAM wParam,<br>   LPARAM lParam);</p> <p>该函数将一条消息放入到指定U程的消息队列中Qƈ且不{到消息被该U程处理时便q回?br>idThreadQ将接收消息的线E的IDQ?<br>MsgQ指定用来发送的消息Q?<br>wParamQ同消息有关的字参数Q?<br>lParamQ同消息有关的长参数Q?<br>调用该函数时Q如果即接收消息的U程没有创徏消息循环Q则该函数执行失败?/p> <p>四、Win32 API多线E编E例E?/p> <p>例程1 MultiThread1</p> <p>建立一个基于对话框的工EMultiThread1Q在对话框IDD_MULTITHREAD1_DIALOG中加入两个按钮和一个编辑框Q两个按钮的ID分别是IDC_STARTQIDC_STOP Q标题分别ؓ“启动”Q?#8220;停止”QIDC_STOP的属性选中DisabledQ编辑框的ID为IDC_TIME Q属性选中Read-onlyQ?br>  <br>在MultiThread1Dlg.h文g中添加线E函数声明: void ThreadFunc();</p> <p>注意Q线E函数的声明应在cCMultiThread1Dlg的外部?在类CMultiThread1Dlg内部dprotected型变量:  HANDLE hThread;<br> DWORD ThreadID;</p> <p>分别代表U程的句柄和ID?<br>  <br>在MultiThread1Dlg.cpp文g中添加全局变量m_bRun Q?volatile BOOL m_bRun;</p> <p>m_bRun 代表U程是否正在q行?/p> <p>你要留意到全局变量 m_bRun 是?volatile 修饰W的Qvolatile 修饰W的作用是告诉编译器无需对该变量作Q何的优化Q即无需它攑ֈ一个寄存器中,q且该值可被外部改变。对于多U程引用的全局变量来说Qvolatile 是一个非帔R要的修饰W?/p> <p>~写U程函数Q?void ThreadFunc()<br>{<br> CTime time;<br> CString strTime;<br> m_bRun=TRUE;<br> while(m_bRun)<br> {<br>  time=CTime::GetCurrentTime();<br>  strTime=time.Format("%H:%M:%S");<br>  ::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_TIME,strTime);<br>  Sleep(1000);<br> }<br>}</p> <p>该线E函数没有参敎ͼ也不q回函数倹{只要m_bRun为TRUEQ线E一直运行?/p> <p>双击IDC_START按钮Q完成该按钮的消息函敎ͼ void CMultiThread1Dlg::OnStart() <br>{<br> // TODO: Add your control notification handler code here<br> hThread=CreateThread(NULL,<br>  0,<br>  (LPTHREAD_START_ROUTINE)ThreadFunc,<br>  NULL,<br>  0,<br>  &ThreadID);<br> GetDlgItem(IDC_START)->EnableWindow(FALSE);<br> GetDlgItem(IDC_STOP)->EnableWindow(TRUE);</p> <p>}</p> <p>双击IDC_STOP按钮Q完成该按钮的消息函敎ͼ void CMultiThread1Dlg::OnStop() <br>{<br> // TODO: Add your control notification handler code here<br> m_bRun=FALSE;<br> GetDlgItem(IDC_START)->EnableWindow(TRUE);<br> GetDlgItem(IDC_STOP)->EnableWindow(FALSE);<br>}</p> <p>~译q运行该例程Q体会用Win32 API~写的多U程?</p> <p> </p> <p>例程2 MultiThread2</p> <p>  该线E演CZ如何传送一个一个整型的参数C个线E中Q以及如何等待一个线E完成处理?/p> <p>建立一个基于对话框的工EMultiThread2Q在对话框IDD_MULTITHREAD2_DIALOG中加入一个编辑框和一个按钮,ID分别是IDC_COUNTQIDC_START Q按钮控件的标题?#8220;开?#8221;Q?<br>在MultiThread2Dlg.h文g中添加线E函数声明: void ThreadFunc(int integer);</p> <p>注意Q线E函数的声明应在cCMultiThread2Dlg的外部?/p> <p>在类CMultiThread2Dlg内部dprotected型变?  HANDLE hThread;<br> DWORD ThreadID;</p> <p>分别代表U程的句柄和ID?br>  <br>打开ClassWizardQؓ~辑框IDC_COUNTdint型变量m_nCount。在MultiThread2Dlg.cpp文g中添加:void ThreadFunc(int integer)<br>{<br> int i;<br> for(i=0;i<integer;i++)<br> {<br>  Beep(200,50);<br>  Sleep(1000);<br> }<br>} </p> <p>双击IDC_START按钮Q完成该按钮的消息函敎ͼ void CMultiThread2Dlg::OnStart() <br>{<br> UpdateData(TRUE);<br> int integer=m_nCount;<br> hThread=CreateThread(NULL,<br>  0,<br>  (LPTHREAD_START_ROUTINE)ThreadFunc,<br>  (VOID*)integer,<br>  0,<br>  &ThreadID);<br> GetDlgItem(IDC_START)->EnableWindow(FALSE);<br> WaitForSingleObject(hThread,INFINITE);<br> GetDlgItem(IDC_START)->EnableWindow(TRUE);<br>}</p> <p>Z说一下WaitForSingleObject函数Q其函数原型为:DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);</p> <p>hHandle监视的对象(一般ؓ同步对象Q也可以是线E)的句柄; <br>dwMilliseconds为hHandle对象所讄的超时|单位为毫U; <br>  当在某一U程中调用该函数ӞU程暂时挂vQ系l监视hHandle所指向的对象的状态。如果在挂v的dwMilliseconds毫秒内,U程所{待的对象变为有信号状态,则该函数立即q回Q如果超时时间已l到达dwMilliseconds毫秒Q但hHandle所指向的对象还没有变成有信L态,函数照样q回。参数dwMilliseconds有两个具有特D意义的|0和INFINITE。若?Q则该函数立卌回;若ؓINFINITEQ则U程一直被挂vQ直到hHandle所指向的对象变为有信号状态时为止?br>  本例E调用该函数的作用是按下IDC_START按钮后,一直等到线E返回,再恢复IDC_START按钮正常状态。编译运行该例程q细心体会?/p> <p>例程3 MultiThread3 <br>传送一个结构体l一个线E函C是可能的Q可以通过传送一个指向结构体的指针参数来完成。先定义一个结构体Q?</p> <p>typedef struct<br>{<br> int firstArgu,<br> long secondArgu,<br>…<br>}myType,*pMyType;</p> <p>创徏U程时CreateThread(NULL,0,threadFunc,pMyType,…);<br>在threadFunc函数内部Q可以?#8220;强制转换”Q?/p> <p>int intValue=((pMyType)lpvoid)->firstArgu;<br>long longValue=((pMyType)lpvoid)->seconddArgu;<br>……</p> <p>例程3 MultiThread3演C如何传送一个指向结构体的指针参数?</p> <p>建立一个基于对话框的工EMultiThread3Q在对话框IDD_MULTITHREAD3_DIALOG中加入一个编辑框IDC_MILLISECONDQ一个按钮IDC_STARTQ标题ؓ“开?#8221; Q一个进度条IDC_PROGRESS1Q?<br>打开ClassWizardQؓ~辑框IDC_MILLISECONDdint型变量m_nMilliSecondQؓq度条IDC_PROGRESS1dCProgressCtrl型变量m_ctrlProgressQ?<br>在MultiThread3Dlg.h文g中添加一个结构的定义Q?struct threadInfo<br>{<br> UINT nMilliSecond;<br> CProgressCtrl* pctrlProgress;<br>};</p> <p>U程函数的声明: UINT ThreadFunc(LPVOID lpParam);</p> <p>注意Q二者应在类CMultiThread3Dlg的外部?</p> <p>在类CMultiThread3Dlg内部dprotected型变? HANDLE hThread;<br>DWORD ThreadID;</p> <p>分别代表U程的句柄和ID?<br>在MultiThread3Dlg.cpp文g中进行如下操作:</p> <p>定义公共变量 threadInfo InfoQ?br>双击按钮IDC_STARTQ添加相应消息处理函敎ͼvoid CMultiThread3Dlg::OnStart() <br>{<br> // TODO: Add your control notification handler code here</p> <p> UpdateData(TRUE);<br> Info.nMilliSecond=m_nMilliSecond;<br> Info.pctrlProgress=&m_ctrlProgress;</p> <p> hThread=CreateThread(NULL,<br>  0,<br>  (LPTHREAD_START_ROUTINE)ThreadFunc,<br>  &Info,<br>  0,<br>  &ThreadID);<br>/*<br> GetDlgItem(IDC_START)->EnableWindow(FALSE);<br> WaitForSingleObject(hThread,INFINITE);<br> GetDlgItem(IDC_START)->EnableWindow(TRUE);<br>*/<br>}</p> <p>在函数BOOL CMultiThread3Dlg::OnInitDialog()中添加语句: {<br> ……<br> <br> // TODO: Add extra initialization here<br> m_ctrlProgress.SetRange(0,99);<br> m_nMilliSecond=10;<br> UpdateData(FALSE);<br> return TRUE;  // return TRUE  unless you set the focus to a control<br>}</p> <p>dU程处理函数QUINT ThreadFunc(LPVOID lpParam) {<br> threadInfo* pInfo=(threadInfo*)lpParam;<br> for(int i=0;i<100;i++)<br> {<br>  int nTemp=pInfo->nMilliSecond;</p> <p>  pInfo->pctrlProgress->SetPos(i);</p> <p>  Sleep(nTemp);<br> }<br> return 0;<br>}</p> <p>  Z补充一点,如果你在void CMultiThread3Dlg::OnStart() 函数中添?* */语句Q编译运行你׃发现q度条不q行hQ主U程也停止了反应。什么原因呢Q这是因为WaitForSingleObject函数{待子线E(ThreadFuncQ结束时Q导致了U程死锁。因为WaitForSingleObject函数会将ȝE挂PM消息都得不到处理Q,而子U程ThreadFunc正在讄q度条,一直在{待ȝE将h消息处理完毕q回才会通知事g。这样两个线E都在互相等待,死锁发生了,~程时应注意避免?<br>例程4 MultiThread4<br>该例E测试在Windows下最多可创徏U程的数目?</p> <p><br>建立一个基于对话框的工EMultiThread4Q在对话框IDD_MULTITHREAD4_DIALOG中加入一个按钮IDC_TEST和一个编辑框IDC_COUNTQ按钮标题ؓ“试” Q?~辑框属性选中Read-onlyQ?<br>在MultiThread4Dlg.cpp文g中进行如下操作:</p> <p>d公共变量volatile BOOL m_bRunFlag=TRUE; <br>该变量表C是否还能l创建线E?/p> <p>dU程函数Q?</p> <p>DWORD WINAPI threadFunc(LPVOID threadNum)<br>{<br> while(m_bRunFlag)<br> {<br>  Sleep(3000);<br> }<br> return 0;<br>}</p> <p>只要 m_bRunFlag 变量为TRUEQ线E一直运行?/p> <p>双击按钮IDC_TESTQ添加其响应消息函数Qvoid CMultiThread4Dlg::OnTest() <br>{<br> DWORD threadID;<br> GetDlgItem(IDC_TEST)->EnableWindow(FALSE);<br> long nCount=0;<br> while(m_bRunFlag)<br> {<br>  if(CreateThread(NULL,0,threadFunc,NULL,0,&threadID)==NULL)<br>  {<br>   m_bRunFlag=FALSE;<br>   break;<br>  }<br>  else<br>  {<br>   nCount++;<br>  }<br> }<br>   //不断创徏U程Q直到再不能创徏为止<br> m_nCount=nCount;<br> UpdateData(FALSE);<br> Sleep(5000);<br>   //延时5U,{待所有创建的U程l束<br> GetDlgItem(IDC_TEST)->EnableWindow(TRUE);<br>    m_bRunFlag=TRUE;<br>}</p> <p>五、MFC对多U程~程的支?/p> <p>  MFC中有两类U程Q分别称之ؓ工作者线E和用户界面U程。二者的主要区别在于工作者线E没有消息@环,而用L面线E有自己的消息队列和消息循环?br>  工作者线E没有消息机Ӟ通常用来执行后台计算和维护Q务,如冗长的计算q程Q打印机的后台打印等。用L面线E一般用于处理独立于其他U程执行之外的用戯入,响应用户及系l所产生的事件和消息{。但对于Win32的API~程而言Q这两种U程是没有区别的Q它们都只需U程的启动地址卛_启动U程来执行Q务?br>  在MFC中,一般用全局函数AfxBeginThread()来创建ƈ初始化一个线E的q行Q该函数有两U重载Ş式,分别用于创徏工作者线E和用户界面U程。两U重载函数原型和参数分别说明如下Q?</p> <p>(1) CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,<br>                      LPVOID pParam,<br>                      nPriority=THREAD_PRIORITY_NORMAL,<br>                      UINT nStackSize=0,<br>                      DWORD dwCreateFlags=0,<br>                      LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);</p> <p>PfnThreadProc:指向工作者线E的执行函数的指针,U程函数原型必须声明如下Q?UINT ExecutingFunction(LPVOID pParam);</p> <p>h意,ExecutingFunction()应返回一个UINTcd的|用以指明该函数结束的原因。一般情况下Q返?表明执行成功?<br>pParamQ传递给U程函数的一?2位参敎ͼ执行函数用某种方式解释该倹{它可以是数|或是指向一个结构的指针Q甚臛_以被忽略Q?<br>nPriorityQ线E的优先U。如果ؓ0Q则U程与其父线E具有相同的优先U; <br>nStackSize:U程己分配堆栈的大小Q其单位为字节。如果nStackSize被设?Q则U程的堆栈被讄成与父线E堆栈相同大; <br>dwCreateFlagsQ如果ؓ0Q则U程在创建后立刻开始执行。如果ؓCREATE_SUSPENDQ则U程在创建后立刻被挂P <br>lpSecurityAttrsQ线E的安全属性指针,一般ؓNULLQ?<br> (2) CWinThread* AfxBeginThread(CRuntimeClass* pThreadClass,<br>                      int nPriority=THREAD_PRIORITY_NORMAL,<br>                      UINT nStackSize=0,<br>                      DWORD dwCreateFlags=0,<br>                      LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);</p> <p><br>  pThreadClass 是指?CWinThread 的一个导出类的运行时cd象的指针Q该导出cd义了被创建的用户界面U程的启动、退出等Q其它参数的意义同Ş?。用函数的q个原型生成的线E也有消息机Ӟ在以后的例子中我们将发现同主U程的机制几乎一栗?/p> <p>下面我们对CWinThreadcȝ数据成员及常用函数进行简要说明?</p> <p>m_hThreadQ当前线E的句柄Q?<br>m_nThreadID:当前U程的IDQ?<br>m_pMainWndQ指向应用程序主H口的指?<br>BOOL CWinThread::CreateThread(DWORD dwCreateFlags=0,<br>UINT nStackSize=0,<br>LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);</p> <p>  该函C的dwCreateFlags、nStackSize、lpSecurityAttrs参数和API函数CreateThread中的对应参数有相同含义,该函数执行成功,q回?|否则q回0?br>  一般情况下Q调用AfxBeginThread()来一ơ性地创徏q启动一个线E,但是也可以通过两步法来创徏U程Q首先创建CWinThreadcȝ一个对象,然后调用该对象的成员函数CreateThread()来启动该U程?</p> <p>virtual BOOL CWinThread::InitInstance();</p> <p>  重蝲该函C控制用户界面U程实例的初始化。初始化成功则返回非0|否则q回0。用L面线E经帔R载该函数Q工作者线E一般不使用InitInstance()?virtual int CWinThread::ExitInstance();</p> <p>  在线E终l前重蝲该函数进行一些必要的清理工作。该函数q回U程的退出码Q?表示执行成功Q非0值用来标识各U错误。同InitInstance()成员函数一P该函C只适用于用L面线E?<br>六、MFC多线E编E实?/p> <p>  在Visual C++ 6.0~程环境中,我们既可以编写C风格?2位Win32应用E序Q也可以利用MFCcd~写C++风格的应用程序,二者各有其优缺炏V基于Win32的应用程序执行代码小巧,q行效率高,但要求程序员~写的代码较多,且需要管理系l提供给E序的所有资源;而基于MFCcd的应用程序可以快速徏立v应用E序Q类库ؓE序员提供了大量的封装类Q而且Developer Studio为程序员提供了一些工h理用户源程序,其缺Ҏ(gu)cd代码很庞大。由于用类库所带来的快速、简捷和功能强大{优性,因此除非有特D的需要,否则Visual C++推荐使用MFCcdq行E序开发?/p> <p>我们知道QMFC中的U程分ؓ两种Q用L面线E和工作者线E。我们将分别举例说明?/p> <p>?MFC cd~程实现工作者线E?/p> <p>例程5 MultiThread5</p> <p>Z与Win32 API对照Q我们用MFC cd~程实现例程3 MultiThread3?/p> <p>建立一个基于对话框的工EMultiThread5Q在对话框IDD_MULTITHREAD5_DIALOG中加入一个编辑框IDC_MILLISECONDQ一个按钮IDC_STARTQ标题ؓ“开?#8221; Q一个进度条IDC_PROGRESS1Q?<br>打开ClassWizardQؓ~辑框IDC_MILLISECONDdint型变量m_nMilliSecondQؓq度条IDC_PROGRESS1dCProgressCtrl型变量m_ctrlProgressQ?<br>在MultiThread5Dlg.h文g中添加一个结构的定义Q?struct threadInfo<br>{<br> UINT nMilliSecond;<br> CProgressCtrl* pctrlProgress;<br>};</p> <p>U程函数的声明:UINT ThreadFunc(LPVOID lpParam); <br>注意Q二者应在类CMultiThread5Dlg的外部?/p> <p>在类CMultiThread5Dlg内部dprotected型变量:</p> <p>CWinThread* pThread; <br>在MultiThread5Dlg.cpp文g中进行如下操作:定义公共变量QthreadInfo Info; <br>双击按钮IDC_STARTQ添加相应消息处理函敎ͼ</p> <p>void CMultiThread5Dlg::OnStart() <br>{<br> // TODO: Add your control notification handler code here</p> <p> UpdateData(TRUE);<br> Info.nMilliSecond=m_nMilliSecond;<br> Info.pctrlProgress=&m_ctrlProgress;</p> <p> pThread=AfxBeginThread(ThreadFunc,<br>  &Info);<br>}</p> <p>在函数BOOL CMultiThread3Dlg::OnInitDialog()中添加语句: {<br> ……<br> <br> // TODO: Add extra initialization here<br> m_ctrlProgress.SetRange(0,99);<br> m_nMilliSecond=10;<br> UpdateData(FALSE);<br> return TRUE;  // return TRUE  unless you set the focus to a control<br>}</p> <p>dU程处理函数Q?UINT ThreadFunc(LPVOID lpParam)<br>{<br> threadInfo* pInfo=(threadInfo*)lpParam;<br> for(int i=0;i<100;i++)<br> {<br>  int nTemp=pInfo->nMilliSecond;</p> <p>  pInfo->pctrlProgress->SetPos(i);</p> <p>  Sleep(nTemp);<br> }<br> return 0;<br>}<br>?MFC cd~程实现用户界面U程</p> <p>创徏用户界面U程的步骤:</p> <p>使用ClassWizard创徏cCWinThread的派生类Q以CUIThreadcMؓ例) class CUIThread : public CWinThread<br>{<br> DECLARE_DYNCREATE(CUIThread)<br>protected:<br> CUIThread();           // protected constructor used by dynamic creation</p> <p>// Attributes<br>public:</p> <p>// Operations<br>public:</p> <p>// Overrides<br> // ClassWizard generated virtual function overrides<br> //{{AFX_VIRTUAL(CUIThread)<br> public:<br> virtual BOOL InitInstance();<br> virtual int ExitInstance();<br> //}}AFX_VIRTUAL</p> <p>// Implementation<br>protected:<br> virtual ~CUIThread();</p> <p> // Generated message map functions<br> //{{AFX_MSG(CUIThread)<br>  // NOTE - the ClassWizard will add and remove member functions here.<br> //}}AFX_MSG</p> <p> DECLARE_MESSAGE_MAP()<br>};</p> <p>重蝲函数InitInstance()和ExitInstance()?BOOL CUIThread::InitInstance()<br>{<br> CFrameWnd* wnd=new CFrameWnd;<br> wnd->Create(NULL,"UI Thread Window");<br> wnd->ShowWindow(SW_SHOW);<br> wnd->UpdateWindow();<br> m_pMainWnd=wnd;<br> return TRUE;<br>}</p> <p>创徏新的用户界面U程 void CUIThreadDlg::OnButton1() <br>{<br> CUIThread* pThread=new CUIThread();<br> pThread->CreateThread();<br>}</p> <p>h意以下两点:</p> <p>A、在UIThreadDlg.cpp的开头加入语句: #include "UIThread.h"<br>B、把UIThread.h中类CUIThread()的构造函数的Ҏ(gu)由 protected 改ؓ public?<br>  用户界面U程的执行次序与应用E序ȝE相同,首先调用用户界面U程cȝInitInstance()函数Q如果返回TRUEQl调用线E的Run()函数Q该函数的作用是q行一个标准的消息循环Qƈ且当收到WM_QUIT消息后中断,在消息@环过E中QRun()函数到U程I闲Ӟ没有消息Q,也将调用OnIdle()函数Q最后Run()函数q回QMFC调用ExitInstance()函数清理资源?br>  你可以创Z个没有界面而有消息循环的线E,例如Q你可以从CWinThreadz一个新c,在InitInstance函数中完成某Q务ƈq回FALSEQ这表示仅执行InitInstance函数中的d而不执行消息循环Q你可以通过q种Ҏ(gu)Q完成一个工作者线E的功能?</p> <p>例程6 MultiThread6</p> <p>建立一个基于对话框的工EMultiThread6Q在对话框IDD_MULTITHREAD6_DIALOG中加入一个按钮IDC_UI_THREADQ标题ؓ“用户界面U程” <br>叛_工程q中“New Class…”为工E添加基cMؓCWinThreadzU程cCUIThread?<br>l工E添加新对话框IDD_UITHREADDLGQ标题ؓ“U程对话?#8221;?<br>为对话框IDD_UITHREADDLG创徏一个基于CDialog的类CUIThreadDlg。用ClassWizard为CUIThreadDlgcL加WM_LBUTTONDOWN消息的处理函数OnLButtonDownQ如下: void CUIThreadDlg::OnLButtonDown(UINT nFlags, CPoint point) <br>{<br> AfxMessageBox("You Clicked The Left Button!");<br> CDialog::OnLButtonDown(nFlags, point);<br>}<br>在UIThread.h中添?#include "UIThreadDlg.h"<br>q在CUIThreadcMdprotected变量CUIThread m_dlgQ?class CUIThread : public CWinThread<br>{<br> DECLARE_DYNCREATE(CUIThread)<br>protected:<br> CUIThread();           // protected constructor used by dynamic creation</p> <p>// Attributes<br>public:</p> <p>// Operations<br>public:</p> <p>// Overrides<br> // ClassWizard generated virtual function overrides<br> //{{AFX_VIRTUAL(CUIThread)<br> public:<br> virtual BOOL InitInstance();<br> virtual int ExitInstance();<br> //}}AFX_VIRTUAL</p> <p>// Implementation<br>protected:<br> CUIThreadDlg m_dlg;<br> virtual ~CUIThread();</p> <p> // Generated message map functions<br> //{{AFX_MSG(CUIThread)<br>  // NOTE - the ClassWizard will add and remove member functions here.<br> //}}AFX_MSG</p> <p> DECLARE_MESSAGE_MAP()<br>};</p> <p>分别重蝲InitInstance()函数和ExitInstance()函数Q?BOOL CUIThread::InitInstance()<br>{<br> m_dlg.Create(IDD_UITHREADDLG);<br> m_dlg.ShowWindow(SW_SHOW);<br> m_pMainWnd=&m_dlg;<br> return TRUE;<br>}</p> <p>int CUIThread::ExitInstance()<br>{<br> m_dlg.DestroyWindow();<br> return CWinThread::ExitInstance();<br>}</p> <p>双击按钮IDC_UI_THREADQ添加消息响应函敎ͼ void CMultiThread6Dlg::OnUiThread() <br>{<br> CWinThread *pThread=AfxBeginThread(RUNTIME_CLASS(CUIThread));<br>}</p> <p>q在MultiThread6Dlg.cpp的开头添加: #include "UIThread.h"</p> <p>  好了Q编译ƈq行E序吧。每单击一?#8220;用户界面U程”按钮Q都会弹Z个线E对话框Q在M一个线E对话框内按下鼠标左键,都会弹出一个消息框?br>七、线E间通讯</p> <p>  一般而言,应用E序中的一个次要线ELZU程执行特定的Q?q样,ȝE和ơ要U程间必定有一个信息传递的渠道,也就是主U程和次要线E间要进行通信。这U线E间的通信不但是难以避免的Q而且在多U程~程中也是复杂和频繁的,下面进行说明?</p> <p>使用全局变量q行通信</p> <p>׃属于同一个进E的各个U程׃n操作pȝ分配该进E的资源Q故解决U程间通信最单的一U方法是使用全局变量。对于标准类型的全局变量Q我们徏议用volatile 修饰W,它告诉编译器无需对该变量作Q何的优化Q即无需它攑ֈ一个寄存器中,q且该值可被外部改变。如果线E间所需传递的信息较复杂,我们可以定义一个结构,通过传递指向该l构的指针进行传递信息?br>  <br>使用自定义消?/p> <p>我们可以在一个线E的执行函数中向另一个线E发送自定义的消息来辑ֈ通信的目的。一个线E向另外一个线E发送消息是通过操作pȝ实现的。利用Windows操作pȝ的消息驱动机Ӟ当一个线E发Z条消息时Q操作系l首先接收到该消息,然后把该消息转发l目标线E,接收消息的线E必dl徏立了消息循环?<br>例程7 MultiThread7 </p> <p>  该例E演CZ如何使用自定义消息进行线E间通信。首先,ȝE向CCalculateThreadU程发送消息WM_CALCULATEQCCalculateThreadU程收到消息后进行计,再向ȝE发送WM_DISPLAY消息Q主U程收到该消息后昄计算l果?</p> <p>建立一个基于对话框的工EMultiThread7Q在对话框IDD_MULTITHREAD7_DIALOG中加入三个单选按钮IDC_RADIO1QIDC_RADIO2QIDC_RADIO3Q标题分别ؓ1+2+3+4+......+10Q?+2+3+4+......+50Q?+2+3+4+......+100。加入按钮IDC_SUMQ标题ؓ“求和”。加入标{框IDC_STATUSQ属性选中“Ҏ(gu)”Q?<br>在MultiThread7Dlg.h中定义如下变量: protected:<br> int nAddend;</p> <p>代表加数的大?/p> <p>分别双击三个单选按钮,d消息响应函数Qvoid CMultiThread7Dlg::OnRadio1() <br>{<br> nAddend=10;<br>}</p> <p>void CMultiThread7Dlg::OnRadio2() <br>{<br> nAddend=50;<br> <br>}</p> <p>void CMultiThread7Dlg::OnRadio3() <br>{<br> nAddend=100;<br> <br>}<br>q在OnInitDialog函数中完成相应的初始化工作: BOOL CMultiThread7Dlg::OnInitDialog()<br>{<br>……<br> ((CButton*)GetDlgItem(IDC_RADIO1))->SetCheck(TRUE);<br> nAddend=10;<br>……</p> <p>在MultiThread7Dlg.h中添加: #include "CalculateThread.h"<br>#define WM_DISPLAY WM_USER+2<br>class CMultiThread7Dlg : public CDialog<br>{<br>// Construction<br>public:<br> CMultiThread7Dlg(CWnd* pParent = NULL); // standard constructor<br> CCalculateThread* m_pCalculateThread;<br>……<br>protected:<br> int nAddend;<br> LRESULT OnDisplay(WPARAM wParam,LPARAM lParam);<br>……</p> <p>在MultiThread7Dlg.cpp中添加: BEGIN_MESSAGE_MAP(CMultiThread7Dlg, CDialog)<br>……<br> ON_MESSAGE(WM_DISPLAY,OnDisplay)<br>END_MESSAGE_MAP()</p> <p>LRESULT CMultiThread7Dlg::OnDisplay(WPARAM wParam,LPARAM lParam)<br>{<br> int nTemp=(int)wParam;<br> SetDlgItemInt(IDC_STATUS,nTemp,FALSE);</p> <p>  return 0;</p> <p>}<br>以上代码使得ȝE类CMultiThread7Dlg可以处理WM_DISPLAY消息Q即在IDC_STATUS标签框中昄计算l果?<br>双击按钮IDC_SUMQ添加消息响应函敎ͼ void CMultiThread7Dlg::OnSum() <br>{<br> m_pCalculateThread=<br>  (CCalculateThread*)AfxBeginThread(RUNTIME_CLASS(CCalculateThread));</p> <p> Sleep(500);</p> <p> m_pCalculateThread->PostThreadMessage(WM_CALCULATE,nAddend,NULL);<br>}<br>OnSum()函数的作用是建立CalculateThreadU程Qg时给该线E发送WM_CALCULATE消息?<br>叛_工程q中“New Class…”为工E添加基cMؓ CWinThread zU程c?CCalculateThread?/p> <p>在文件CalculateThread.h 中添?#define WM_CALCULATE WM_USER+1 <br>class CCalculateThread : public CWinThread<br>{<br>……<br>protected:<br> afx_msg LONG OnCalculate(UINT wParam,LONG lParam);<br>……</p> <p>在文件CalculateThread.cpp中添?LONG CCalculateThread::OnCalculate(UINT wParam,LONG lParam)<br>{<br> int nTmpt=0;<br> for(int i=0;i<=(int)wParam;i++)<br> {<br>  nTmpt=nTmpt+i;<br> }</p> <p> Sleep(500);<br>    ::PostMessage((HWND)(GetMainWnd()->GetSafeHwnd()),WM_DISPLAY,nTmpt,NULL);</p> <p> return 0;<br>}<br>BEGIN_MESSAGE_MAP(CCalculateThread, CWinThread)<br> //{{AFX_MSG_MAP(CCalculateThread)<br>  // NOTE - the ClassWizard will add and remove mapping macros here.<br> //}}AFX_MSG_MAP<br> ON_THREAD_MESSAGE(WM_CALCULATE,OnCalculate)<br>//和主U程Ҏ(gu)Q注意它们的区别<br>END_MESSAGE_MAP()</p> <p>在CalculateThread.cpp文g的开头添加一条: #include "MultiThread7Dlg.h"</p> <p>  以上代码为 CCalculateThread cL加了 WM_CALCULATE 消息Q消息的响应函数?OnCalculateQ其功能是根据参?wParam 的|q行累加Q篏加结果在临时变量nTmpt中,延时0.5U,向主U程发送WM_DISPLAY消息q行昄QnTmpt作ؓ参数传递?<br>~译q运行该例程,体会如何在线E间传递消息?<br>八、线E的同步</p> <p>  虽然多线E能l我们带来好处,但是也有不少问题需要解冟뀂例如,对于像磁盘驱动器q样独占性系l资源,׃U程可以执行q程的Q何代码段Q且U程的运行是ql调度自动完成的Q具有一定的不确定性,因此有可能出现两个U程同时对磁盘驱动器q行操作Q从而出现操作错误;又例如,对于银行pȝ的计机来说Q可能用一个线E来更新其用h据库Q而用另外一个线E来d数据库以响应储户的需要,极有可能L据库的线E读取的是未完全更新的数据库Q因为可能在ȝ时候只有一部分数据被更新过?/p> <p>  佉K属于同一q程的各U程协调一致地工作UCؓU程的同步。MFC提供了多U同步对象,下面我们只介l最常用的四U: </p> <p>临界区(CCriticalSectionQ?<br>事gQCEventQ?<br>互斥量(CMutexQ?<br>信号量(CSemaphoreQ?br>  <br>通过q些c,我们可以比较Ҏ(gu)地做到线E同步?</p> <p>A、?CCriticalSection c?</p> <p>  当多个线E访问一个独占性共享资源时,可以使用“临界?#8221;对象。Q一时刻只有一个线E可以拥有界区对象Q拥有界区的线E可以访问被保护h的资源或代码D,其他希望q入临界区的U程被挂v{待Q直到拥有界区的线E放弃界区时ؓ止,q样׃证了不会在同一时刻出现多个U程讉K׃n资源?/p> <p>CCriticalSectioncȝ用法非常单,步骤如下Q?br>  </p> <p>定义CCriticalSectioncȝ一个全局对象Q以使各个线E均能访问)Q如CCriticalSection critical_sectionQ?<br>在访问需要保护的资源或代码之前,调用CCriticalSectioncȝ成员LockQ)获得临界区对象: critical_section.Lock();</p> <p>在线E中调用该函数来使线E获得它所h的界区。如果此时没有其它线E占有界区对象Q则调用Lock()的线E获得界区Q否则,U程被挂vQƈ攑օC个系l队列中{待Q直到当前拥有界区的线E释放了临界区时为止?<br>讉K临界区完毕后Q用CCriticalSection的成员函数Unlock()来释放界区Qcritical_section.Unlock();</p> <p>再通俗一点讲Q就是线EA执行到critical_section.Lock();语句Ӟ如果其它U程(B)正在执行critical_section.Lock();语句后且critical_section. Unlock();语句前的语句ӞU程A׃{待Q直到线EB执行完critical_section. Unlock();语句Q线EA才会l箋执行?<br>下面再通过一个实例进行演C明?/p> <p><br>例程8 MultiThread8</p> <p>建立一个基于对话框的工EMultiThread8Q在对话框IDD_MULTITHREAD8_DIALOG中加入两个按钮和两个~辑框控Ӟ两个按钮的ID分别为IDC_WRITEW和IDC_WRITEDQ标题分别ؓ“?#8216;W’”?#8220;?#8216;D’”Q两个编辑框的ID分别为IDC_W和IDC_DQ属性都选中Read-onlyQ?<br>在MultiThread8Dlg.h文g中声明两个线E函敎ͼ UINT WriteW(LPVOID pParam);<br>UINT WriteD(LPVOID pParam);</p> <p>使用ClassWizard分别lIDC_W和IDC_DdCEditcd量m_ctrlW和m_ctrlDQ?<br>在MultiThread8Dlg.cpp文g中添加如下内容:</p> <p>Z文g中能够正用同步类Q在文g开头添加:#include "afxmt.h"</p> <p>定义临界区和一个字W数l,Z能够在不同线E间使用Q定义ؓ全局变量QCCriticalSection critical_section;<br>char g_Array[10];</p> <p>dU程函数QUINT WriteW(LPVOID pParam)<br>{<br> CEdit *pEdit=(CEdit*)pParam;<br> pEdit->SetWindowText("");<br> critical_section.Lock();<br> //锁定临界区,其它U程遇到critical_section.Lock();语句时要{待<br> //直至执行critical_section.Unlock();语句<br> for(int i=0;i<10;i++)<br> {<br>  g_Array[i]=''W'';<br>     pEdit->SetWindowText(g_Array);<br>  Sleep(1000);<br> }<br> critical_section.Unlock();<br> return 0;</p> <p>}</p> <p>UINT WriteD(LPVOID pParam)<br>{<br> CEdit *pEdit=(CEdit*)pParam;<br> pEdit->SetWindowText("");<br> critical_section.Lock();<br> //锁定临界区,其它U程遇到critical_section.Lock();语句时要{待<br> //直至执行critical_section.Unlock();语句<br> for(int i=0;i<10;i++)<br> {<br>  g_Array[i]=''D'';<br>     pEdit->SetWindowText(g_Array);<br>  Sleep(1000);<br> }<br> critical_section.Unlock();<br> return 0;</p> <p>}<br>分别双击按钮IDC_WRITEW和IDC_WRITEDQ添加其响应函数Q?void CMultiThread8Dlg::OnWritew() <br>{<br> CWinThread *pWriteW=AfxBeginThread(WriteW,<br>  &m_ctrlW,<br>  THREAD_PRIORITY_NORMAL,<br>  0,<br>  CREATE_SUSPENDED);<br> pWriteW->ResumeThread();<br>}</p> <p>void CMultiThread8Dlg::OnWrited() <br>{<br> CWinThread *pWriteD=AfxBeginThread(WriteD,<br>  &m_ctrlD,<br>  THREAD_PRIORITY_NORMAL,<br>  0,<br>  CREATE_SUSPENDED);<br> pWriteD->ResumeThread();<br> <br>}<br>׃代码较简单,不再详述。编译、运行该例程Q?zhn)可以q箋点击两个按钮Q观察体会界类的作用?<br>B、?CEvent c?</p> <p>  CEvent cL供了对事件的支持。事件是一个允怸个线E在某种情况发生Ӟ唤醒另外一个线E的同步对象。例如在某些|络应用E序中,一个线E(CؓAQ负责监听通讯端口Q另外一个线E(CؓBQ负责更新用h据。通过使用CEvent c,U程A可以通知U程B何时更新用户数据。每一个CEvent 对象可以有两U状态:有信L态和无信L态。线E监视位于其中的CEvent cd象的状态,q在相应的时候采取相应的操作?br>  在MFC中,CEvent cd象有两种cdQh工事件和自动事g。一个自动CEvent 对象在被臛_一个线E释攑֐会自动返回到无信L态;而h工事件对象获得信号后Q释攑֏利用U程Q但直到调用成员函数ReSetEvent()才将其设|ؓ无信L态。在创徏CEvent cȝ对象Ӟ默认创徏的是自动事g?CEvent cȝ各成员函数的原型和参数说明如下:</p> <p>1、CEvent(BOOL bInitiallyOwn=FALSE,<br>          BOOL bManualReset=FALSE,<br>          LPCTSTR lpszName=NULL,<br>          LPSECURITY_ATTRIBUTES lpsaAttribute=NULL);</p> <p><br>bInitiallyOwn:指定事g对象初始化状态,TRUE为有信号QFALSE为无信号Q?<br>bManualResetQ指定要创徏的事件是属于人工事gq是自动事g。TRUEZh工事ӞFALSE动事Ӟ <br>后两个参C般设为NULLQ在此不作过多说明?<br>2、BOOL CEventQ:SetEvent();</p> <p>  ?CEvent cd象的状态设|ؓ有信L态。如果事件是人工事gQ则 CEvent cd象保持ؓ有信L态,直到调用成员函数ResetEvent()?光新设为无信号状态时为止。如果CEvent cd象ؓ自动事gQ则在SetEvent()事件设|ؓ有信L态后QCEvent cd象由pȝ自动重置为无信号状态?/p> <p>如果该函数执行成功,则返回非零|否则q回零?3、BOOL CEventQ:ResetEvent();<br>  该函数将事g的状态设|ؓ无信L态,q保持该状态直至SetEvent()被调用时为止。由于自动事件是ql自动重|,故自动事件不需要调用该函数。如果该函数执行成功Q返回非零|否则q回零。我们一般通过调用WaitForSingleObject函数来监视事件状态。前面我们已l介l了该函数。由于语a描述的原因,CEvent cȝ理解实有些隑ֺQ但(zhn)只要通过仔细玩味下面例程Q多看几遍就可理解?<br>例程9 MultiThread9</p> <p>建立一个基于对话框的工EMultiThread9Q在对话框IDD_MULTITHREAD9_DIALOG中加入一个按钮和两个~辑框控Ӟ按钮的ID为IDC_WRITEWQ标题ؓ“?#8216;W’”Q两个编辑框的ID分别为IDC_W和IDC_DQ属性都选中Read-only; <br>在MultiThread9Dlg.h文g中声明两个线E函敎ͼ UINT WriteW(LPVOID pParam);<br>UINT WriteD(LPVOID pParam);</p> <p>使用ClassWizard分别lIDC_W和IDC_DdCEditcd量m_ctrlW和m_ctrlDQ?<br>在MultiThread9Dlg.cpp文g中添加如下内容: <br>Z文g中能够正用同步类Q在文g开头添?</p> <p>#include "afxmt.h"</p> <p>定义事g对象和一个字W数l,Z能够在不同线E间使用Q定义ؓ全局变量?CEvent eventWriteD;<br>char g_Array[10];</p> <p>dU程函数Q?UINT WriteW(LPVOID pParam)<br>{<br> CEdit *pEdit=(CEdit*)pParam;<br> pEdit->SetWindowText("");<br> for(int i=0;i<10;i++)<br> {<br>  g_Array[i]=''W'';<br>     pEdit->SetWindowText(g_Array);<br>  Sleep(1000);<br> }<br> eventWriteD.SetEvent();<br> return 0;</p> <p>}<br>UINT WriteD(LPVOID pParam)<br>{<br> CEdit *pEdit=(CEdit*)pParam;<br> pEdit->SetWindowText("");<br> WaitForSingleObject(eventWriteD.m_hObject,INFINITE);<br> for(int i=0;i<10;i++)<br> {<br>  g_Array[i]=''D'';<br>     pEdit->SetWindowText(g_Array);<br>  Sleep(1000);<br> }<br> return 0;</p> <p>}</p> <p>  仔细分析q两个线E函? (zhn)就会正理解CEvent cR线EWriteD执行?WaitForSingleObject(eventWriteD.m_hObject,INFINITE);处等待,直到事geventWriteD为有信号该线E才往下执行,因ؓeventWriteD对象是自动事Ӟ则当WaitForSingleObject()q回Ӟpȝ自动把eventWriteD对象重置为无信号状态?<br>双击按钮IDC_WRITEWQ添加其响应函数Q?void CMultiThread9Dlg::OnWritew() <br>{<br> CWinThread *pWriteW=AfxBeginThread(WriteW,<br>  &m_ctrlW,<br>  THREAD_PRIORITY_NORMAL,<br>  0,<br>  CREATE_SUSPENDED);<br> pWriteW->ResumeThread();</p> <p> CWinThread *pWriteD=AfxBeginThread(WriteD,<br>  &m_ctrlD,<br>  THREAD_PRIORITY_NORMAL,<br>  0,<br>  CREATE_SUSPENDED);<br> pWriteD->ResumeThread();<br> <br>}<br>~译q运行程序,单击“?#8216;W’”按钮Q体会事件对象的作用?<br>C、用CMutex c?/p> <p>  互斥对象与界区对象很像.互斥对象与界区对象的不同在?互斥对象可以在进E间使用,而界区对象只能在同一q程的各U程间用。当Ӟ互斥对象也可以用于同一q程的各个线E间Q但是在q种情况下,使用临界Z更节省系l资源,更有效率?/p> <p>D、用CSemaphore c?/p> <p>  当需要一个计数器来限制可以用某个线E的数目Ӟ可以使用“信号?#8221;对象。CSemaphore cȝ对象保存了对当前讉K某一指定资源的线E的计数|该计数值是当前q可以用该资源的线E的数目。如果这个计数达CӞ则所有对q个CSemaphore cd象所控制的资源的讉K试都被攑օC个队列中{待Q直到超时或计数g为零时ؓ止。一个线E被释放已访问了被保护的资源Ӟ计数值减1Q一个线E完成了对被控共享资源的讉KӞ计数值增1。这个被CSemaphore cd象所控制的资源可以同时接受访问的最大线E数在该对象的构建函C指定?/p> <p>CSemaphore cȝ构造函数原型及参数说明如下Q?</p> <p>CSemaphore (LONG lInitialCount=1,<br>            LONG lMaxCount=1,<br>            LPCTSTR pstrName=NULL,<br>            LPSECURITY_ATTRIBUTES lpsaAttributes=NULL);</p> <p>lInitialCount:信号量对象的初始计数|卛_讉KU程数目的初始| <br>lMaxCountQ信号量对象计数值的最大|该参数决定了同一时刻可访问由信号量保护的资源的线E最大数目; <br>后两个参数在同一q程中用一般ؓNULLQ不作过多讨论; <br>  在用CSemaphore cȝ构造函数创Z号量对象时要同时指出允许的最大资源计数和当前可用资源计数。一般是当前可用资源计数设|ؓ最大资源计敎ͼ每增加一个线E对׃n资源的访问,当前可用资源计数׃?Q只要当前可用资源计数是大于0的,可以发Z号量信号。但是当前可用计数减到0Ӟ则说明当前占用资源的U程数已l达C所允许的最大数目,不能再允许其它线E的q入Q此时的信号量信号将无法发出。线E在处理完共享资源后Q应在离开的同旉过ReleaseSemaphore()函数当前可用资源数??/p> <p>下面l出一个简单实例来说明 CSemaphore cȝ用法?/p> <p>例程10 MultiThread10</p> <p>建立一个基于对话框的工EMultiThread10Q在对话框IDD_MULTITHREAD10_DIALOG中加入一个按钮和三个~辑框控Ӟ按钮的ID为IDC_STARTQ标题ؓ“同时?#8216;A’?#8216;B’?#8216;C’”Q三个编辑框的ID分别为IDC_A、IDC_B和IDC_CQ属性都选中Read-onlyQ?<br>在MultiThread10Dlg.h文g中声明两个线E函敎ͼ UINT WriteA(LPVOID pParam);<br>UINT WriteB(LPVOID pParam);<br>UINT WriteC(LPVOID pParam); <br>使用ClassWizard分别lIDC_A、IDC_B和IDC_CdCEditcd量m_ctrlA、m_ctrlB和m_ctrlCQ?<br>在MultiThread10Dlg.cpp文g中添加如下内容: <br>Z文g中能够正用同步类Q在文g开头添加:</p> <p>#include "afxmt.h"</p> <p>定义信号量对象和一个字W数l,Z能够在不同线E间使用Q定义ؓ全局变量QCSemaphore semaphoreWrite(2,2); //资源最多访问线E?个,当前可访问线E数2?<br>char g_Array[10]; <br>d三个U程函数Q?</p> <p>UINT WriteA(LPVOID pParam)<br>{<br> CEdit *pEdit=(CEdit*)pParam;<br> pEdit->SetWindowText("");<br> WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);<br> CString str;<br> for(int i=0;i<10;i++)<br> {<br>        pEdit->GetWindowText(str);<br>  g_Array[i]=''A'';<br>  str=str+g_Array[i];<br>     pEdit->SetWindowText(str);<br>  Sleep(1000);<br> }<br> ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);<br> return 0;</p> <p>}<br>UINT WriteB(LPVOID pParam)<br>{<br> CEdit *pEdit=(CEdit*)pParam;<br> pEdit->SetWindowText("");<br> WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);<br> CString str;<br> for(int i=0;i<10;i++)<br> {</p> <p>        pEdit->GetWindowText(str);<br>  g_Array[i]=''B'';<br>  str=str+g_Array[i];<br>     pEdit->SetWindowText(str);<br>  Sleep(1000);<br> }<br> ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);<br> return 0;</p> <p>}<br>UINT WriteC(LPVOID pParam)<br>{<br> CEdit *pEdit=(CEdit*)pParam;<br> pEdit->SetWindowText("");<br> WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);<br> for(int i=0;i<10;i++)<br> {<br>  g_Array[i]=''C'';<br>     pEdit->SetWindowText(g_Array);<br>  Sleep(1000);<br> }<br> ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);<br> return 0;</p> <p>}</p> <p>q三个线E函C再多说。在信号量对象有信号的状态下Q线E执行到WaitForSingleObject语句处l执行,同时可用U程数减1Q若U程执行到WaitForSingleObject语句时信号量对象无信PU程在q里{待Q直C号量对象有信LE才往下执行?<br>双击按钮IDC_STARTQ添加其响应函数Q?void CMultiThread10Dlg::OnStart() <br>{<br> CWinThread *pWriteA=AfxBeginThread(WriteA,<br>  &m_ctrlA,<br>  THREAD_PRIORITY_NORMAL,<br>  0,<br>  CREATE_SUSPENDED);<br> pWriteA->ResumeThread();</p> <p> CWinThread *pWriteB=AfxBeginThread(WriteB,<br>  &m_ctrlB,<br>  THREAD_PRIORITY_NORMAL,<br>  0,<br>  CREATE_SUSPENDED);<br> pWriteB->ResumeThread();</p> <p> CWinThread *pWriteC=AfxBeginThread(WriteC,<br>  &m_ctrlC,<br>  THREAD_PRIORITY_NORMAL,<br>  0,<br>  CREATE_SUSPENDED);<br> pWriteC->ResumeThread();</p> <p><br>}</p> <p>好吧Q多U程~程׃l到q里Q希望本文能Ҏ(gu)有所帮助?br></p> <img src ="http://www.shnenglu.com/bhjjkg/aggbug/89132.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/bhjjkg/" target="_blank">Wood_K</a> 2009-07-03 07:56 <a href="http://www.shnenglu.com/bhjjkg/archive/2009/07/03/89132.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>递归_字符串压~与解压{大ACM2571——Big String Outspread}http://www.shnenglu.com/bhjjkg/archive/2009/05/19/83396.htmlWood_KWood_KTue, 19 May 2009 09:27:00 GMThttp://www.shnenglu.com/bhjjkg/archive/2009/05/19/83396.htmlhttp://www.shnenglu.com/bhjjkg/comments/83396.htmlhttp://www.shnenglu.com/bhjjkg/archive/2009/05/19/83396.html#Feedback0http://www.shnenglu.com/bhjjkg/comments/commentRss/83396.htmlhttp://www.shnenglu.com/bhjjkg/services/trackbacks/83396.html 点击q入该题?br>

 1#include <stdio.h>
 2void work(char str[1001],int k,int rec)
 3{
 4    int i;
 5    int j;
 6    int kuo;
 7    while(rec--)
 8    {
 9        for(i = k;str[i] != ')' && str[i] != '\0';)
10        {
11            if(str[i] - 'a' >= 0 && str[i] - 'z' <= 25/*字母*/
12                {printf("%c",str[i]);i++;}
13            else if(str[i] == '('/*括号---递归调用*/
14            {
15                work(str,i + 1,1);
16                for(kuo = 1,i += 1;kuo != 0;i++)
17                    {
18                        if(str[i] == '(')kuo++;
19                        if(str[i] == ')')kuo--;
20                    }

21            }

22            else /*数字*/
23                if(str[i + 1- 'a' >= 0 && str[i + 1- 'a' <= 25/*数字+字母*/ 
24                {
25                    for(j = 0;j < str[i] - '0';j++)
26                        printf("%c",str[i + 1]);
27                    i += 2;
28                }

29                else if(str[i + 1== '('/*数字+括号---递归调用*/
30                {
31                    work(str,i + 2,str[i] - '0');
32                    for(kuo = 1,i += 2;kuo != 0;i++)
33                    {
34                        if(str[i] == '(')kuo++;
35                        if(str[i] == ')')kuo--;
36                    }

37                }

38            }

39        }

40    }

41}

42int main()
43{
44    int T;
45    char str[1001];
46    scanf("%d",&T);
47    getchar();
48    while(T--)
49    {
50        gets(str);
51        work(str,0,1);
52        printf("\n");
53    }

54}

  通过递归巧妙的递归调用化了解题步骤

Wood_K 2009-05-19 17:27 发表评论
]]>
þþþùһ| þ99ۺϾƷŮͬ| aëƬ÷˾þ| ƷƷþþþ| պһþþþþ| þùƷ͵99| Ļձ޾þþ | Ʒþþþþô| þ| ĻþþƷ| þùѹۿƷ3| AVۺϾþ| ӰȷŮAV³ɫԴþ| þùƷþþƷ| þùƷ| avھƷþþþӰԺ| Ʒҹþ| ھƷþ޻| ݺɫþþۺƵպ| 㽶þҹɫƷС˵| þۺϾɫۺվ| պŷ޹ƷĻþþ| ޷AVþò| 97þþþ| ɫۺϺϾþۺӿ| þ޾Ʒ˳ۺ| ٸŮþۺɫ| ˾ҹվھƷþþþþþþ| vaþþþ| þþƷav鶹ͼƬ | AëƬþþƷ| þֻоƷ18| þþƷAVDz18| һɫþ88ۺպƷ | þٸ۲AV | þҹɫƷ| þþƷ5555| þþþþƷĻ | þþ| þ99ëƬѹۿ| þƵվ|