C++本身已经提供了多线程接口,这位老哥的文章写得异常的清晰,请直接移步。
下面的东西年代比较久远,是调用Windows的API实现的,虽然也没有错,但还是不如直接用C++的API好,当然如果只需要考虑Windows的程序,也可以略为参考。
---------------------------------
不知道大家在 MFC 编程时有没有遇到过这样一个问题,当一个程序用到比较复杂的计算或者仅仅就是触发一个死循环,整个画面就卡死在那里不动了?这是因为程序一直在执行着该计算,根本无暇对其他的消息做出响应,这样导致的结果是用户体验非常差,而且程序效率十分低下。多线程可以帮助我们解决这个问题,其原理是操作系统分出不同线程对应的时间片,当一个线程执行到一定的时间后程序切换到另外的线程去执行该线程的程序,这样反复快速的切换,让用户有种多条线程同时在跑的感觉。
MFC中有两类线程,一为工作者线程、一为用户界面线程。二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。由于本人只使用过工作者线程,是故暂时只做工作者线程相关的记录。下面为跑起线程的代码:
在程序对话框类定义中(添加为全局函数也可以)添加如下三个函数:
private: //多线程
void RunThread();
static UINT ThreadFun(LPVOID lpParam);
void ThreadRun();
在cpp文件中分别对三个函数进行定义
void CMFC_TESTDlg::RunThread()
{
CWinThread* pThread;//线程指针对象
pThread = AfxBeginThread(ThreadFun, (void *)this);//开启一个工作者线程,ThreadFun为线程的入口函数
}
UINT CMFC_TESTDlg::ThreadFun(LPVOID lpParam)
{
CMFC_TESTDlg *dlg = (CMFC_TESTDlg *)lpParam;
dlg->ThreadRun();//调用线程的处理函数
return 0;
}
void CMFC_TESTDlg::ThreadRun()
{
//线程处理函数主体部分,将要该线程需要处理的代码添加在这个位置
}
定义完上面三个函数之后,工作线程的声明和定义工作就已经完成了,可以在程序中想要启用多线程的地方调用 RunThread() 让线程跑起来。
当然,我们可以对第一个函数进行封装,将所有的线程开启都通过这个函数来进行操作,则我们将线程函数声明为:
void RunThread(int threadID);
然后添加指代线程标志的宏定义如下:
#define DECODETHRAEDONE 1 //解码线程一
#define DECODETHRAEDTWO 2 //解码线程二
这样,通过判别传入线程标志可分别开启不同线程,函数定义如下:
void CPanoramicPlayer20Dlg::RunThread(int threadID)
{
CWinThread* pThread;
switch (threadID)
{
case DECODETHRAEDONE://解码线程
pThread = AfxBeginThread(ThreadDecodeImageFun1, (void *)this);
pThread->SetThreadPriority(THREAD_PRIORITY_HIGHEST);
break;
case DECODETHRAEDTWO:
pThread = AfxBeginThread(ThreadDecodeImageFun2, (void *)this);
pThread->SetThreadPriority(THREAD_PRIORITY_HIGHEST);
break;
default:
break;
}
}
这样通过修改线程接口函数就OK了,如下:
UINT CPanoramicPlayer20Dlg::ThreadDecodeImageFun1(LPVOID lpParam)
{
CPanoramicPlayer20Dlg *dlg = (CPanoramicPlayer20Dlg *)lpParam;
dlg->ThreadRun();//调用线程的响应函数,其实如果愿意,也可以忽略掉这两句话,直接将多线程的处理内容加在这里,这样做是为了让多线程的调用层次看起来更加的明显
return 0;
}
UINT CPanoramicPlayer20Dlg::ThreadDecodeImageFun2(LPVOID lpParam)
{
CPanoramicPlayer20Dlg *dlg = (CPanoramicPlayer20Dlg *)lpParam;
dlg->ThreadRun();//调用线程的响应函数,其实如果愿意,也可以忽略掉这两句话,直接将多线程的处理内容加在这里,这样做是为了让多线程的调用层次看起来更加的明显
return 0;
}
在多线程中,线程之间共同访问一块内存是常有的事,这个时候需要加上线程临界区来保护该内存以免发生冲突或者内存错误。首先,定义线程临界区对象如下:
CCriticalSection g_clsCriticalSection;//线程临界区对象
其次,将需要保护的相关操作放在线程临界区里面就OK了,具体如下:
g_clsCriticalSection.Lock();
/*保护内容放在里面*/
g_clsCriticalSection.Unlock();
这里需要特别注意的是,同一个线程临界区对象在一个线程进入临界区之后别的线程就无法进入,哪怕保护的数据并不一样。也就是说,如果要保护的对象有多个,应该使用不同的线程临界区对象!!!这一点十分重要!!!
相对而言,控制台程序则简单些,下面是一般的调用方式
DWORD WINAPI run1(LPVOID lpParamter)
{
while (true)
{
printf("线程1\n");
Sleep(1000);
}
}
DWORD WINAPI run2(LPVOID lpParamter)
{
while (true)
{
printf("线程2\n");
Sleep(1000);
}
}
void main()
{
HANDLE hThread = CreateThread(NULL, 0, SendUdp, NULL, 0, NULL);
CloseHandle(hThread);
hThread = CreateThread(NULL, 0, run2, NULL, 0, NULL);
CloseHandle(hThread);
while (1)
{
Sleep(100000);
}
return;
}
本文深入解析了C++多线程编程原理,包括如何在MFC中创建和管理线程,以及如何避免多线程冲突。通过提供具体的代码示例,详细展示了如何在实际应用中运用多线程技术提升程序性能。

被折叠的 条评论
为什么被折叠?



