注:实习期间的关于多线程方面的笔记,只是自己的理解,不一定权威正确。请读者慎重,请谅解。
一、
MFC多线程
可以通过AfxBeginThread创建用户界面线程或者工作者线程
工作者线程例子:
AfxBeginThread函数说明:
AfxBeginThread( AFX_THREADPROC pfnThreadProc, //启动的函数
LPVOID pParam, //pParam : 传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程.
int nPriority = THREAD_PRIORITY_NORMAL, //0 设置优先级为正常。
UINT nStackSize = 0, //指定新创建的线程的栈的大小.如果为 0,新创建的线程具有和主线程一样的大小的栈
DWORD dwCreateFlags , //指定创建线程以后,线程有怎么样的标志.可以指定两个值CREATE_SUSPENDED : 线程创建以后,会处于挂起状态,直到调用:ResumeThread;0 : 创建线程后就开始运行.
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL ); //如果为 NULL,那么新创建的线程就具有和主线程一样的安全性.
创建线程:
CWinThread *m_MyThread; //线程
m_MyThread=AfxBeginThread((AFX_THREADPROC)ThreadProc, NULL,0,0,CREATE_SUSPENDED,NULL);
//线程结束时不自动删除,才能获得lpExitCode,默认是TRUE
m_MyThread->m_bAutoDelete = FALSE;
m_MyThread->ResumeThread();
线程定义:
//线程函数
UINT WINAPI ThreadProc(LPVOID lpParameter)
{
while(1)
{
//可以通过Event信号对象或者bool值信号判断线程关闭条件
if(WaitForSingleObject(g_Dev.m_ThreadEvent, 0) == WAIT_OBJECT_0)
{
AfxEndThread(0); //关闭线程,后面的就不执行了
//break;
}
Sleep(10);
。。。。。
}
return0;
}
二、
获取线程结束代码
调用GetExitCodeThread()(并给予CreateThread所获得的线程handle作为参数)而得知:
BOOL GetExitCodeThread(
HANDLE hThread, //某线程
LPDWORD lpExitCode //线程退出代码
);
hThread:由CreateThread()传回的线程handle
lpExitCode:用于存储线程的返回值(exitcode)
返回值:该函数执行成功则返回非0值,否则返回 0(FALSE)
用法:
定义 DWORD lpExitCode=0;
线程函数定义如下:
DWORD WINAPI ThreadFunc(LPVOID n)
{
Sleep((DWORD)n*1000*2);
return 100;
}
结束线程如下:
AfxEndThread(lpExitCode); //关闭线程
注解:
if( lpExitCode== STILL_ACTIVE ) //STILL_ACTIVE表示线程在运行
trace("Thread1 is still running!");
if( lpExitCode!= STILL_ACTIVE ) //线程已经结束
或者
if( lpExitCode== 100) //100为前面线程函数的返回值return值
附:
线程的handle用处:
线程的handle是指向“线程的内核对象”的,而不是指向线程本身.每个内核对象只是内核分配的一个内存块,并且只能由内核访问。该内存块是一种数据结构,它的成员负责维护对象的各种信息(eg: 安全性描述,引用计数等)。
CloseHandle()
在CreateThread成功之后会返回一个hThread的handle,且内核对象的计数加1,CloseHandle之后,引用计数减1,当变为0时,系统删除内核对象。 但是这个handle并不能完全代表这个线程,它仅仅是线程的一个“标识”,系统和用户可以利用它对相应的线程进行必要的操纵。如果在线程成功创建后,不再需要用到这个句柄,就可以在创建成功后,线程退出前直接CloseHandle掉,但这并不会影响到线程的运行。关闭句柄后,线程并没关闭。
不执行CloseHandle() 带来的后果:
若在线程执行完之后,没有通过CloseHandle()将引用计数减1,在进程执行期间,将会造成内核对象的泄露,相当与句柄泄露,但不同于内存泄露, 这势必会对系统的效率带来一定程度上的负面影响。但是,因为CWinThread::m_bAutoDelete缺省是TRUE,不需要显式CloseHandle()。但这是一个良好的编程习惯!
结束线程函数
三、
WaitForSingleObject 的用法
DWORD WaitForSingleObject
(
HANDLE hHandle,
DWORDdwMilliseconds
);
参数hHandle 是一个某事件的句柄,第二个参数 dwMilliseconds 是时间间隔。如果事件A是有信号状态,则返回,返回WAIT_OBJECT_0 ,如果时间超过 dwMilliseconds 值,但事件还是无信号状态,则返回,返回 WAIT_TIMEOUT 。
用法:
//一旦事件对象处于有信号状态立即break
if(::WaitForSingleObject(g_End, 0) == WAIT_OBJECT_0)
{
break;
}
用法二、
WaitForSingleObject(g_event,INFINITE);
For(;;)
{
………… .
}
该线程中,只有g_event变为有信号状态时才执行下面的 for 循环,若g_event 是全局变量,我们可以在别的线程中通过 g_event. SetEvent 控制这个线程。
四、
Event对象
函数原型:
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,//安全属性,NULL为默认的安全属性
BOOL bManualReset,//复位方式,TRUE为手动复位,FALSE为自动复位
BOOL bInitialState,//初始状态,TRUE为初始为有信号,FALSE为无信号
LPCTSTR lpName // 对象名称
);