学习多线程之一:线程通信--利用事件对象作者:龚辉斌 下载本文示例代码在线程之间传送信号可以使用事件对象,用MFC的CEvent来表示。一个事件对象有两种状态:信号态与非信号态。线程能监视于信号态的事件,以便在适当的时间完成对事件的操作。创建事件的语句如下: CEvent ThreadBegin; 事件被创建后就自动处于非信号态,要使用它处于信息态,必须使用对件对象的成员函数SetEvent(),即: ThreadBegin.SetEvent(); 线程监视这个信号来知道事件已准备就绪,从而可以进行其它的操作。而线程通过调用API函数WaitForSingleObject()来监视这个信号。 ::WaitForSingleObject(ThreadBegin.m_hObject,INFINITE); 该函数的两个参数分别表示要检查的事件句柄与函数等待事件时间。INFINITE告诉WaitForSingleObject()在特定的事件不处于信号态时不要返回,即把它放在线程的开始的话,那么系统将挂起这个线程,直到事件处于信号态时才继续执行下去。当已经准备好线程继续执行下去的条件时,调用SetEvent(),当线程获得了相应信号态信号后便会继续执行下去。 一旦线程不再被挂起时,它便可以完成相关事务。但若要在主程序中通过线程结束,那么线程必须监视接下来的这个事件,看它是否处于信号态。线程可以通过对事件进行轮询,这时只要调用WaitForSingleObject()即可,只是等待时间参数的值被置为0,即: ::WaitForSingleObject(ThreadBegin.m_hObject,0); 当返回WAIT_OBJECT_0时,表示事件处于信号态,否则处于非信号态。 UINT ThreadProc(LPVOID param) { ::WaitForSingleObject(ThreadBegin.m_hObject,INFINITE); ::MessageBox((HWND)param,"Thread Activated!","Thread",MB_OK); BOOL KeepRunning=true; while (KeepRunning) { int Result=::WaitForSingleObject(ThreadEnd.m_hObject,0); if (Result==WAIT_OBJECT_0) KeepRunning=false; } ::MessageBox((HWND)param,"Thread Stopped!","Thread",MB_OK); return 0; } 启动线程则用如下代码: HWND hWnd=GetSafeHwnd(); AfxBeginThread(ThreadProc,hWnd); ThreadBegin.SetEvent(); /////////////////////////// 当反复创建这一线程时,程序内存占用会不断增加,…… ( shliwan 发表于 2006-5-21 19:59:00) 这里的代码联接是错的http://www.vckbase.com/code/winsys/mtask/Thread1_23.zip这才是对的! ( lhongliangi 发表于 2004-3-4 14:55:00) 我想的是一进入系统就开始读数据库,进度条就会显示其读写情况.读完后进度条显示完成,然后其数据就添加在LIST控件中.如果没有进度条显示其进度要读7万条的记录程序就好象死机能否给个线程的例子!我做个例子不成功,请教!!void CNEWADODlg::OnBUTTONProgressCtrl() { int ii; int BB; BB=m_pRecordset->RecordCount; m_ProgressCtrl.SetRange(0,BB); for(ii=0;ii<=BB;ii++) { m_ProgressCtrl.SetPos(ii); }}( hjw21 发表于 2003-11-27 9:23:00) 那个while循环会不会很占资源? ( musicfan 发表于 2003-6-24 13:58:00) 你好,我在做一个工控程序用到过你说过的方法,监测一块板卡的脉冲信号,在低速时效果还可以,但达到当频率达到100K以后,就有问题了,监测不准,需要加入一定的偏差量才可以,但有时候误差就比较大了,累计以后就达不到要求拉,不知道你试过没有,也向想你请教一下。 ( wuyuebear 发表于 2003-6-23 9:11:00) .......................................................More... 学习多线程之二:线程同步--使用临界区 下载本文示例源代码临界区是一种保证在某一时刻只有一个线程能访问数据的简便办法。不管哪一个线程占用临界区对象,它都可以访问受保护的数据,而其他线程就必须等待,直到占用临界区的线程进行释放操作,从而临界区的数据是不会一个以上的线程同一时刻访问的。 在MFC中通过CCtiticalSection类来创建临界区实例,如: CCriticalSection CriticalSection; 当线程准备访问临界区的数据时,必须调用它的成员函数Lock()进行锁定,如: CriticalSecion.Lock(); 如果没有任何线程占用临界区,Lock()可以向调用纯种提供临界区数据的访问,当线程完成各项数据操作后,再调用成员函数UnLock()进行释放,别的线程才可以占用临界区。如: CriticalSection.UnLock(); 可以定义一个数据实例:class CDataArray{private: int iArray[10]; CCriticalSection CriticalSection;public: CDataArray(){}; ~CDataArray(){}; void SetData(int iValue); void GetDataArray(int aArray[10]);}; 在头文件中必须包含afxmt.h,它提供了程序对CCriticalSection的访问机制。void CDataArray::SetData(int iValue){ CriticalSection.Lock(); for (int i=0;i<10;i++) iArray[i]=iValue; CriticalSection.Unlock();} void CDataArray::GetDataArray(int aArray[10]){ CriticalSection.Lock(); for (int i=0;i<10;i++) aArray[i]=iArray[i]; CriticalSection.Unlock();} 增加数据实例:CDataArray DataArray; 再编写读写函数:UINT Thread_WriteProc(LPVOID param){ for (int i=0;i<10;i++) { DataArray.SetData(i); ::Sleep(500); } return 0;} UINT Thread_ReadProc(LPVOID param){ int aArray[10]; for (int i=0;i<20;i++) { DataArray.GetDataArray(aArray); char str[255]; str[0]=0; for (int j=0;j<10;j++) { int len=strlen(str); wsprintf(&str[len],"%d",aArray[j]); } ::MessageBox((HWND)param,str,"Thread Read Proc",MB_OK); } return 0;} 这样我们可以启动这两个线程函数:HWND hWnd=GetSafeHwnd();AfxBeginThread(Thread_WriteProc,hWnd);AfxBeginThread(Thread_ReadProc,hWnd); 这样当Thread_WriteProc占用临界区时,Thread_ReadProc必须等待,直到Thread_WriteProc退出了临界区,从而实现线程间的同步。 本文即本人在学习多任务多线程过程的手记,供大家参考,望能得到各位指点。 作者信箱:devvy@21cn.com mahuixing 说的好,写的更好只是class CDataArray{private:int iArray[10];CCriticalSection CriticalSection;public:CDataArray(){};~CDataArray(){}; void SetData(int iValue); void GetDataArray(int aArray[10]);};要改为class CDataArray{private:int iArray[10];public:CDataArray(){};~CDataArray(){}; CCriticalSection CriticalSection; void SetData(int iValue); void GetDataArray(int aArray[10]);};通过谢谢 感谢贴主龚辉斌简单易懂的描述和各们评论的人士... ...( cdq888 发表于 2005-6-15 11:39:00) xw885说的对,MESSAGEBOX应该临界区的UNLOCK前,这个样子就可以在点击OK前锁住写。要将GetDataArray的UNLOCK删除,然后修改下面就可以实现互斥操作UINT Thread_ReadProc(LPVOID param){int aArray[10];for (int i=0;i<20;i++){DataArray.GetDataArray(aArray);...::MessageBox((HWND)param,str,"Thread Read Proc",MB_OK);DataArray.CriticalSection.Unlock();}return 0;}( mahuixing 发表于 2005-3-28 11:01:00) 这个例子的确有问题,他的问题在对话框弹出的时机上,例子程序在堆上锁住线程的,一旦退出方法,锁就失效了,这时弹出对话框时,另一个线程就可以修改全局变量,造成数字跳跃增加,解决方法,将弹出对话框放到UnLock之前,因为MessageBox会阻塞当前线程,这样就不会UnLock,那么另一个线程就无法访问全局变量,问题就解决了 ( xw885 发表于 2005-3-14 19:50:00) 测试结果:不同步我不知道是否理解了你的意思:当鼠标点击一下『确定』时再次弹出的对话框应该只比前一次每位都加一,比如说第一个对话框时000000000,那么第二个对话框就应该时111111111(个数没仔细数),但是我测试时,如果弹出第一个对话框后停留几秒再点『确定』的话,那再次弹出的对话框就不是111111111了。要保正每次点击【确定】后无论等待多长时间再次弹出的对话框数据只比前一次加一的话应该做如下改正再定义两个信号量CSemaphore *m_pSemaphoreFull;CSemaphore *m_pSemaphoreEmpty;为指针分配空间m_pSemaphoreFull = new CSemaphore(1,1);m_pSemaphoreEmpty = new CSemaphore(0,1);分别在SetData()和GetDataArray()函数中加入m_pSemaphoreFull->Lock();//代码....m_pSemaphoreEmpty->Unlock();和m_pSemaphoreEmpty->Lock();//代码....m_pSemaphoreFull->Unlock();这样就能实现我理解的意思了。Windows XP SP2 256M内存 CPU 2.4G 下测试通过 ( 不要只做技术 发表于 2005-3-9 14:34:00)

评论