Win32多线程编程注意事项

本文详细介绍了Win32多线程编程中需要注意的事项,包括线程退出策略,线程间数据传递的方法,如何在类中实现多线程,以及主线程与子线程同步的技巧。强调了线程退出时使用WaitForSingleObject的重要性,线程间数据交换的安全性,以及控制台输入的互斥控制。

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

1、线程退出

(1)使用布尔型变量,如:

volatile BOOL  g_bThreadRun = TRUE;

while(g_bThreadRun)

{

    //处理逻辑

}

隐藏问题: 如果线程执行的时间较长,如循环中Sleep(1000);  这样会导致,执行 g_bThreadRun=FALSE; 后立即执行后面的函数,而不会等待线程结束。

(2)设置布尔型变量为FALSE之后,等待线程结束,再执行其他语句,如:

g_bThreadRun = FALSE;

Sleep(2000);

隐藏问题:这种方式下,只有将Sleep时间给的很长才行,但这样效率很低,并且用户无法让程序立即结束,至少得等Sleep的时间过后才能结束程序,存在着安全隐患。

(3)使用WaitForSingleObject/WaitForMultipleObjects函数,如:

volatile BOOL  g_bThreadRun = TRUE;

//人工事件:一旦将SetEvent之后,等待该事件的所有线程将变成可调度状态

g_hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

while(g_bThreadRun)
{
if( WaitForSingleObject(g_hExitEvent,1) == WAIT_OBJECT_0)
{
//线程退出
break;
}

        //其他处理逻辑

}

2、线程间传送数据

(1)使用由临界区等方式保护的全局变量,如:

int g_nData = 0;

CRITICAL_SECTION g_cs;

InitializeCriticalSection(&g_cs); //创建临界区


            EnterCriticalSection(&g_cs); 
            ... 
            //   操作g_nData
            ... 
            LeaveCriticalSection(&g_cs); 
            return   0; 
}

(2)使用PostThreadMessage函数传递线程消息,如:

PostThreadMessage(g_dwThreadID,WM_MY_MSG,0,(LPARAM)(new string("你好"));

【注】接收消息的线程必须有自己的消息队列,如:

MSG msg = {0};
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);//强制系统创建消息队列
while(g_bThreadRun)
{
if( WaitForSingleObject(g_hExitEvent,1) == WAIT_OBJECT_0)
{
//线程退出
break;
}
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if(msg.message != WM_MY_MSG) //用户自定义消息
{
continue;
}
//获取消息
std::string strMsg = *(std::string*)msg.lParam;
if(msg.lParam != NULL)
{
delete (std::string*)msg.lParam;
msg.lParam = NULL;
}

                //处理消息strMsg

}

3、类中实现多线程

由于线程函数必须是全局性质的,因此要实现类的多线程,则线程函数必须是static类型或类的friend友元函数。

(1)static线程函数

由于static类型成员函数只能访问static成员,因此可通过以下两种方式访问类的非static成员:

1>定义本类类型的static型成员对象指针m_pThis,将其初始化为类的隐含指针this,在线程函数中通过m_pThis访问非static成员。

2>CreateThread时,将类的隐含指针this通过LPVOID参数的形式传递给线程函数,线程函数通过该参数访问非static成员。

(2)friend线程函数

由于friend友元函数是可以访问类所有成员的全局函数,因此只能以参数的形式将this指针传递给线程函数,以便对类成员的访问。

如:

class MyClass

{

public:

     friend  DWORD  WINAPI  MyThread(LPVOID lpParam);

     HANDLE            m_hThread;
     DWORD             m_dwThreadID;

};

m_hThread = CreateThread(NULL, 0, MyThread, this, 0, &m_dwThreadID);

DWORD  WINAPI  MyThread(LPVOID lpParam)
{
if(lpParam == NULL)
{
return -1;
}
MyClass *pThis = (MyClass *) lpParam; 

       //线程处理逻辑

}

4、主线程需要所有子线程结束后才可退出,如果是控制台程序,一般由用户从键盘输入来退出程序。

但子线程中也可能会要求用户输入,此时,需要对控制台输入进行互斥控制。如:

HANDLE        m_hMutexIo;        //控制台输入输出互斥量
BOOL CHttpClient::Wait(const char cStop)
{
if(m_hMutexIo == NULL)
{
m_hMutexIo = CreateMutex(NULL,FALSE,NULL);
if(m_hMutexIo == NULL)
{
return FALSE;
}
}
int c = 0;
while( c != cStop)
{
if( WaitForSingleObject(m_hMutexIo,100) == WAIT_OBJECT_0)
{
c = _getche();
ReleaseMutex(m_hMutexIo);
}
}
if(m_hMutexIo != NULL)
{
CloseHandle(m_hMutexIo);
m_hMutexIo = NULL;
}
return TRUE;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值