多线程个人总结

CreateThread (windows API)

使用此接口一般要求结束时调用CloseHandle关闭句柄.值得注意的是:
如果线程中使用了诸如strtok()等函数(_tiddata结构成员的注释标注了这些函数),C运行库会尝试读取该线程的tiddata,如果没有,则会分配一个。这样在使用CloseHandle()关闭句柄时,tiddata未被释放,造成内存泄露.使用CreatThread()创建,调用_endthreadex()关闭,又显得不匹配。所以还是建议使用_beginthreadex()。

_beginthreadex() (CRT)

_beginthreadex()是_beginthread()的改良版,比如新增设置优先权,创建时挂起等.接口如下:

unsignedlong _beginthreadex(
void *security,									//线程函数的安全描述符
unsigned stack_size,							// 堆栈大小,设置0为系统默认值
unsigned ( __stdcall *start_address )( void * ),//线程函数的起始地址
void*arglist, 									//传递给线程函数的参数,没有则为NULL
unsignedinitflag,								//初始状态,0为立即执行,CREATE_SUSPENDED为创建后挂起
unsigned*thrdaddr );							//指向一个32为的变量,存放线程标识符

_beginthreadex()在也是调用CreateThread()创建线程的,在调用CreateThread()之前会分配一个_tiddata结构用于新建线程使用

_beginthreadex()调用后发生的操作如下:
1、_beginthreadex新建一个tiddata,将线程函数和参数保存到里面,然后调用windows API的CreateThread(),其线程函数为_threadstartex(),参数为tiddata
2、_threadstartex()设置完tiddata后,调用_callthreadstartex()
3、_callthreadstartex()新建了一个SHE异常帧,然后执行_beginthreadex()参数中的线程函数,执行完毕后,调用_endthreadex()
4、_endthreadex()会获取tiddata,然后将其释放,最后调用ExitThread()退出线程.系统不能自动关闭线程句柄,需要手动关闭,相反_endthread会.这样其实也有个好处,那就是对WaitFor系列函数的调用就比较方便了.
注意:
1._beginthreadex()在正常运行结束后,会自动调用_endthreadex(),但不会关闭句柄,需要手动CloseHandle().
2._beginthreadex()的线程函数必须使用__stdcall调用方式,而且必须返回一个unsigned型的退出码
3._beginthreadex()在创建线程失败时返回0,而_beginthread()在创建线程失败时返回-1

AfxBeginThread (MFC)

也是对CreateThread接口的封装.它会new一个CWinThread对象,而且这个对象在线程结束时会自动删除.不便之处是无法获取它的状态.
如果用MFC编程,不要用CreateThread,如果只是使用Runtime Library,用_BegingThreadex,总之,不要轻易使用CreateThread.因为在MFC和CRT中的函数有可能会用到些它们所封装的公用变量.

等待信号

WaitForSingleObject

DWORD WaitForSingleObject( HANDLE hHandle,DWORDdwMilliseconds);
它可以等待如下几种类型的对象:
Event,Mutex,Semaphore,Process,Thread
有三种返回类型:
WAIT_OBJECT_0, 表示等待的对象有信号(对线程来说,表示执行结束);
WAIT_TIMEOUT, 表示等待指定时间内,对象一直没有信号(线程没执行完);
WAIT_ABANDONED 表示对象有信号,但还是不能执行 一般是因为未获取到锁或其他原因.

WaitForMultiObject

DWORD WaitForMultipleObjects(DWORD nCount, CONST HANDLE *lpHandles, BOOLfWaitAll, DWORDdwMilliseconds);
四个参数分别是:
1.nCount,DWORD类型,用于指定句柄数组的数量
2. lphObjects,Pointer类型,用于指定句柄数组的内存地址
3. fWaitAll,Boolean类型,True表示函数等待所有指定句柄的Object有信号为止
4. dwTimeout,DWORD类型,用于指定等待的Timeout时间,单位毫秒,可以是INFINITE
当WaitForMultipleObjects等待多个内核对象的时候,如果它的bWaitAll 参数设置为false。其返回值减去WAIT_OBJECT_0 就是参数lpHandles数组的序号。如果同时有多个内核对象被触发,这个函数返回的只是其中序号最小的那个。如果为TRUE 则等待所有信号量有效再往下执行.
多个内核对象被触发时,WaitForMultipleObjects选择其中序号最小的返回。而WaitForMultipleObjects它只会改变使它返回的那个内核对象的状态。如果序号最小的那个对象频繁被触发,那么序号比它大的内核对象将得不到被处理的机会,怎么办?可以用双WaitForMultipleObjects检测机制,如下例子:

DWORD WINAPI ThreadProc(LPVOID lpParameter)     
{     
    DWORD dwRet = 0;     
    int nIndex = 0;     
    while(1)     
    {   
        dwRet = WaitForMultipleObjects(nCount,pHandles,false,INFINITE); //返回值范围:WAIT_OBJECT_0至WAIT_OBJECT_0+nCount-1   
        switch(dwRet)     
        {  
            case WAIT_TIMEOUT:     
                break;     
            case WAIT_FAILED:     
                return 1;  
            default:  
            {  
                nIndex = dwRet - WAIT_OBJECT_0;     
                ProcessHanlde(nIndex++);   //同时检测其他的事件     
                while(nIndex < nCount) //nCount事件对象总数     
                {     
                    dwRet = WaitForMultipleObjects(nCount - nIndex,&pHandles[nIndex],false,0);     
                    switch(dwRet)     
                    {  
                        case WAIT_TIMEOUT:     
                            nIndex = nCount; //退出检测,因为没有被触发的对象了.     
                            break;  
                        case WAIT_FAILED:     
                            return 1;     
                        default:  
                        {  
                            nIndex = dwRet - WAIT_OBJECT_0;     
                            ProcessHanlde(nIndex++);     
                        }  
                            break;  
                    }//switch结束  
                }//while结束  
            }//default结束  
                break;  
        }//switch结束  
  
    }//while结束  
    return 0;   
}

注意:WaitForMultiObjects最多只能等待MAXIMUM_WAIT_OBJECTS个kernal objects。MAXIMUM_WAIT_OBJECTS被定义为64,如果超出,可以进行第二次wait,接收剩余的事件.

猜你喜欢

转载自blog.csdn.net/dreamerLLL/article/details/87863447