智能终端定制开发 ad
MTK/瑞芯微/高通-Android,智能模块/智能终端方案商

深度定制各类智能终端和智能硬件产品,提供硬件选型咨询、参考设计、元器件推荐、驱动开发、行业模块集成、操作系统定制与算法集成等软硬件定制服务。
contact.aspx

Android核心板产品覆盖2G、3G、4G通讯,双核、四核、八核CPU,可选的平台有MTK6580、MTK6737、MTK6750等,Android版本有5.1 6.0 7.0等。
contact.aspx

可广泛应用于低端智能POS、安防监控、车载设备、低端智能机器人、智能家居、智能硬件、工业智能手持设备、低端智能对讲设备、低端警务或执法设备、智能穿戴、贩卖机、物流柜、智能门禁系统等行业和设备。
contact.aspx

可提供以太网转串口透传,WIFI转串口透传,蓝牙转串口透传,CAN总线模拟量控制输出模块等。
contact.aspx

带3G或4G通讯功能,运行android系统,有多个串口,可以外挂各种模块:条码扫描、RFID、指纹识别、身份证识别、磁条卡、ID卡、GPS/北斗模块等。
contact.aspx

具有4G通讯功能,多个RS232或RS485接口,以太网接口,USB接口,CAN接口,多个AD输入。基于Android系统智能平台,方便APP应用开发。器件严格选型,运行稳定,质量可靠。
contact.aspx

多线程管理类
[VC 编程] 2008-04-03

作者:谭永光

下载源代码

  由于最近经常搞些跟线程有关的东西,感觉多线程确实麻烦,线程间要处理好同步与通讯,如果用CWinThread好一点,直接是一个线程对象,如果用AfxBeginThread,那必须定个全局函数,或者写个静态函数,一般是传个this指针进去,然后再用这个指针调用本类函数的成员函数,用起来比较麻烦,现在问题是能不能不用全局或者静态函数来实现呢,于是我实现了这个类,来所简化多线程的创建和关闭的操作。

现在简要看一下类的数据和成员函数

template<class T> class CYGMulThread { protected: typedef void (T::* _pThreadFunc)(void ); static _pThreadFunc ThreadFunc; static BOOL s_IsBreaking; //用以判断线程是否要中断 static CWaitDlg s_Waitdlg;//等待对话框 //内部线程 static UINT ThreadProc(LPVOID lpParam); public: //在线程内部使用,用以判断有没有要结束的信号 static BOOL IsBreakThread() ; //----------------------------非静态 protected: CYGMulThread(); virtual ~CYGMulThread(); CWinThread **m_pThread;//线程数组指针 int m_nThreadCount; //处理windows的消息 void PeekMessageLoop(); public: int GetThreadCount() const ; //pFunc=输入一个void f(void)的成员函数,nThreadCount=线程数目 void YGBeginFuncThread(_pThreadFunc pFunc,int nThreadCount); //结束线程时调用 bool EndAllThread(const char *szMsg); };

一、这里先说一下这个类的使用方法

class CMulThreadDlg : public CDialog,private CYGMulThread { // Construction public: CMulThreadDlg(CWnd* pParent = NULL); // standard constructor void ReleaseShow2(); void ReleaseShow(); void ThreadFunc(); // Dialog Data //{{AFX_DATA(CMulThreadDlg) enum { IDD = IDD_MULTHREAD_DIALOG }; CYGEdit m_edShow; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMulThreadDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: HICON m_hIcon; // Generated message map functions //{{AFX_MSG(CMulThreadDlg) virtual BOOL OnInitDialog(); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg void OnBtnDebug(); afx_msg void OnBtnStop(); afx_msg void OnBtnTest1(); afx_msg void OnBtnTest2(); //}}AFX_MSG DECLARE_MESSAGE_MAP() };

这里要注意两个地方:
1.CYGMulThread的模板是用被派生出来的类,这里的好处,就是可以使CYGMulThread可以使用被派生出来的东西,至于还有什么好处,有兴趣的朋友可以看一下ATL和WTL里的代码,里面大量使用这种结构。

2.这里用的私有继承,当然也可以用公用继承:),个人觉得这样私有继承,数据封装性好一点。

CMulThreadDlg有了这样的头定义后,就可以使用下面的行为了

void CMulThreadDlg::ThreadFunc() { DWORD dwID=GetCurrentThreadId(); while (1) { // g_cs1.Lock(); TRACE("线程:%x\t路过\n",dwID); // g_cs1.Unlock(); Sleep(200); if (IsBreakThread()) { // g_cs1.Lock(); TRACE("线程:%x要结束了!\n",dwID); // g_cs1.Unlock(); return ; } Sleep(10000); } } //创建线程 void CMulThreadDlg::OnBtnDebug() { YGBeginFuncThread(ThreadFunc,10);//创建10个线程,其函数为ThreadFunc,这里ThreadFunc是CMulThreadDlg的成员函数 } //结束线程 void CMulThreadDlg::OnBtnStop() { EndAllThread("正要结束线程...."); }
二、下面说明一下代码的内容

其实创建线程的操作很简单,最令人烦不胜烦的地方是结束线程的代码。
一般其流程是:

1.通知所以线程要结束
2.等待所以线程结束

通知其实倒挺好通知,问题是等待!
第一个问题,主线程界面,考虑的第一个函数是WaitForMultipleObjects,问题是主线用这个函数等待子线程结束时,令主线程会处于休眠状态,如果等待时间长的话,程序就会像死了似的。于是把函数换为MsgWaitForMultipleObjects,令其每次只等待一个线程,而且将其参数bWaitAll设为FALSE,并在调用这个函数前,用PeekMessageLoop处理完Windows留下的消息,这样主界面看起来就不会出问题 。

第二个问题,句柄的复制,因为在MsgWaitForMultipleObjects里,需要输入要等待线程的句柄数组,但AfxBeginThread开启的线程,当线程结束后,其线程句柄就无效,句柄不能普通地赋值,只能用DuplicateHandle将其复制 。

第三个问题,提示,当主线程长时间等待子线程时,是不是应有个提示框之类的东西提示呢,然后主主界面的任何其它操作都不能用,就像我们平时用MessageBox时,我们只能先把这个Box去掉之后,才能操作界面的其它东西,但这里不用这个方法,这里只能Create一个非模态对话框,但这个框要达到像模态对话框的效果,我用spy++看了一下才看想到原来可以这样

//pWnd是主界面的指针 pWnd->EnableWindow(false); //Create一个非模态对话框 //等待所以线程结束 pWnd->EnableWindow(true); pWnd->ShowWindow(SW_RESTORE);

下面是主要代码:

bool EndAllThread(const char *szMsg) { if (!m_pThread) return false;//线程句柄为空 HANDLE pProcess=GetCurrentProcess(); BOOL bRet; int i(0),nRet; HANDLE *pHandle=new HANDLE[m_nThreadCount]; T *pWnd=static_cast<T *>(this); pWnd->EnableWindow(false); if (szMsg) { s_Waitdlg.m_strshow=szMsg; s_Waitdlg.SetCancelDisable();//使取消按钮无效 s_Waitdlg.Create((char *)IDD_YGDIALOG_WAITING,pWnd); s_Waitdlg.CenterWindow(NULL); s_Waitdlg.ShowWindow(SW_SHOW); } for(i=0;i<m_nThreadCount;i++) { //将句柄复制 bRet=DuplicateHandle(pProcess,m_pThread[i]->m_hThread,pProcess,&pHandle[i],DUPLICATE_SAME_ACCESS, true,DUPLICATE_SAME_ACCESS); //保证所复制的句柄都要有效 if (!bRet) { Sleep(100); TRACE("----------------DuplicateHandle 失败!\n"); i--;continue; } } s_IsBreaking=true;//将线程结束 i=0; //等待线程结束 while (i!=m_nThreadCount)//直到所以线程的m_hThread都已经结束时则i==m_nThreadCount { for(i=0;i<m_nThreadCount;i++) { PeekMessageLoop();//先处理多余的Windows消息 //这里一定要用MsgWaitForMultipleObjects,不能用WaitForMultipleObjects,因为这个不能处理消息 nRet=MsgWaitForMultipleObjects(1,pHandle+i,false,INFINITE,QS_ALLEVENTS); TRACE("nRet=%d,i=%d\n",nRet,i); if (nRet==WAIT_OBJECT_0+1) //只有消息Event,没有线程的Event { Sleep(20); //等会儿 break; } if (nRet==WAIT_FAILED ) break;//发生错误,无须等待了 } if (nRet==WAIT_FAILED ) break; } delete [] m_pThread; delete [] pHandle; m_pThread=NULL; m_nThreadCount=0; pWnd->EnableWindow(true); pWnd->ShowWindow(SW_RESTORE); if (IsWindow(s_Waitdlg.m_hWnd)) s_Waitdlg.DestroyWindow(); if (nRet==WAIT_FAILED ) false; return true; }

结束:

  本人文笔不好,以上内容表达可能错漏百出,请各大蝦不要见笑,详细还是见代码吧,如程序有什么问题请用下面的方式联系。
无数遍想不搞MFC,搞界面用MFC确实麻烦,但又舍不得C++。看了几下搞界面好的Delphi,但它PASCAL语法实在让人难以接受,语法功能太弱,就连变量声明的位置都受到限制,操作符重载居然不支持,模板就更不用说了。用.net,把C++扩展了,搞得不知道像个什么样子,还不如用C#,但C#里没有了指针,内存申请了,还不能手动释放,可能我对C#的理解还是很肤浅吧。还是觉得C++是最好计算机语言,但可恶的M$好像要放弃MFC,MFC一直没有什么大的改进,有跟我志同道合的朋友欢迎跟我联系。群:50516594;QQ:158510972

 
[VC 编程添加评论 | 评论/阅读(0/452)
评论
昵称
主页
内容
递交


Copyright @ 我的开发笔记     2008 - 2017         粤ICP备19155526号-1