VC 多线程

本文介绍了多线程编程的基本方法,包括MFC和Win32环境下简单多线程的实现方式,利用二次消息循环模拟多线程技术,以及常见的线程同步手段如临界区、事件、互斥量和信号量的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

一、简单的多线程——不需要同步
 1.1  带参、不需要同步的多线程
  1.1.1  声明线程函数,可以是全局的,也可以是静态的
  UINT ThreadFun(LPVOID lParam);

  1.1. 2  定义一个结构体(也可以是自定义的类),该结构体的各成员是要传递的参数
  struct ThreadInfo{
  int nIndex;
  BOOL bTag;
  };

  1.1.3  定义一个结构体成员:
  ThreadInfo Info;

  1.1.4  在需要启动线程的地方填充结构体成员,并利用AfxBeginThread启动一个线程
  Info.nIndex=wParam;
  Info.bTag=lParam;
  AfxBeginThread(ThreadFun,&Info);

  1.1.5  实现线程函数:
  UINT ThreadFun(LPVOID lParam)
  {
   ThreadInfo* pInfo=(ThreadInfo*)lParam;//获取数据
   CString strTmp="";
   strTmp.Format("%d %d/r/n",pInfo->nIndex,pInfo->bTag);
   AfxMessageBox(strTmp);
   return 0;
  }

 1.2 不带参、不需要同步的多线程
  1.2.1  声明线程函数:UINT ThreadFun(LPVOID lParam);

  1.2.2  在需要启动线程的地方启动线程:AfxBeginThread(ThreadFun,NULL);
 
  1.2.3  实现线程函数:
  UINT ThreadFun(LPVOID lParam)
  {
   AfxMessageBox("不带参、不同步的多线程"); 
  }

二、Win32版多线程——不需要同步
 2.1 声明线程函数
 DWORD WINAPI Func(LPVOID lParam);
 
 2.2 在需要启动线程的地方启动线程:
 HANDLE hThread=CreateThread(NULL,0,Func,NULL,0,NULL);
 CloseHandle(hThread);
 
 2.3 实现线程函数:
 DWORD WINAPI Func(LPVOID lParam)
 {
  AfxMessageBox("Win32多线程");
 }

三、利用二次消息循环模拟实现多线程:
 当应用程序进行复杂计算或占用很多系统资源的操作时,用户点击程序界面按钮时无法响应,有两种解决方法:计算线程,消息循环重载技术,即在应用程序中处理Windows消息循环。这样既可以在主线程中进行复杂计算以满足实时计算要求,又能即使响应用户输入,随时中止计算!
 举例如下:
while(!m_bStop && iStep <= 500) {
      iStep++;
      Sleep(20);
      DoEvents();       // 二次消息循环函数
   }  


void DoEvents()
{
    MSG msg;
    if (::PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { //从Windows消息队列中取出消息
        if (msg.message== WM_QUIT)//如果消息为退出,发送退出消息
        {
            ::PostQuitMessage(-1);
        }
        if(!AfxGetApp()->PreTranslateMessage(&msg))//如果无法预处理消息
        {
            ::TranslateMessage(&msg);//转换消息
            ::DispatchMessage(&msg);//发送消息
        }
    }
    AfxGetApp()->OnIdle(0);
    //AfxGetApp()->OnIdle(1);//消息队列为空时闲置一段时间
}

四、线程同步
MFC提供了多种同步对象,下面是最常用的四种:
临界区(CCriticalSection)
事件(CEvent)
互斥量(CMutex)
信号量(CSemaphore)
参考文章:http://www.vckbase.com/document/viewdoc/?id=1708
 通常在编写多线程程序并需要实现线程同步时,首选临界区,由于他的使用比较简单,而临界区只适用于同一进程中的线程同步,而需要用到不同
进程间的线程同步时,需要使用事件对象或互斥量或信号量。
为了文件中能够正确使用同步类,在文件开头添加:
#include "afxmt.h"
 下面的内容假设已经写出了不需要同步的多线程的代码。
 4.1 使用临界区--任一时刻只有一个线程可以拥有临界区对象
  4.1.1 定义CCriticalSection类的一个全局对象(以使各个线程均能访问)
  4.1.2 在访问需要保护的资源或代码之前,调用CCriticalSection类的成员Lock()
  4.1.3 访问临界区完毕后,使用CCriticalSection的成员函数Unlock()来释放临界区
 4.2 使用事件对象
  在MFC中,CEvent 类对象有两种类型:人工事件和自动事件.一个自动CEvent 对象在被至少一个线程释放后会自动返回到无信号状态;而人工事件对象获得信号后,释放可利用线程,但直到调用成员函数ReSetEvent()才将其设置为无信号状态。在创建CEvent 类的对象时,默认创建的是自动事件。
  如果CEvent对象为自动事件,则在SetEvent()将事件设置为有信号状态后,CEvent 类对象由系统自动重置为无信号状态。
  4.2.1 定义CEvent类的一个全局变量eventWriteD
  4.2.2 在启动线程之前调用eventWriteD.SetEvent();
  4.2.2 在要保护的资源或代码之前,调用WaitForSingleObject(eventWriteD.m_hObject,INFINITE);
  4.2.3 在访问完毕后:eventWriteD.SetEvent();
 4.3 使用互斥对象
   4.3.1 定义一个全局的HANDLE hMutex;
   4.3.2 创建互斥对象:hMutex=CreateMutex(NULL,FALSE,NULL);
   4.3.3 在CreateMutext后ReleaseMutex(hMutex);
   4.3.4 在需要保护的资源代码之前,调用WaitForSingleObject(hMutex,INFINITE);
   4.3.5 在访问完毕后:ReleaseMutex(hMutex);
 4.4 信号量——当需要一个计数器来限制可以使用某个线程的数目时,可以使用“信号量”对象
  4.4.1 定义一个CSemaphore 类的全局变量semaphoreWrite
  4.4.2 在保护代码之前加上:WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);
  4.4.3 在访问完毕后调用:ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值