Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9547449
  • 博文数量: 1227
  • 博客积分: 10026
  • 博客等级: 上将
  • 技术积分: 20273
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-16 12:40
文章分类

全部博文(1227)

文章存档

2010年(1)

2008年(1226)

我的朋友

分类: C/C++

2008-04-23 22:07:45

多线程管理类

作者:

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

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


template

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(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;im_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;iEnableWindow(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

阅读(1819) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~