VC获取子线程入口函数的退出码(分别由CreateThread,_beginthread,_beginthreadex与AfxbeginThread 创建的子线程 )

       在 VC 编程中,若是涉及到多线程编程时,有时我们也需要根据情况获取子线程入口函数的退出码,以便根据具体的程序运行情况做相应的处理。


       之前我在使用 VC 开发程序时,也遇到过需要获取子线程入口函数的退出码的问题,由于起初没有做过相似的程序,所以只会定义一个全局变量来根据情况,在子线程的入口函数里再为其赋予相应的值。虽然这也是一种方法,但根本不能决定根本的问题,而且若程序中的全局变量定义太多的话又容易造成程序的混乱,但是根据线程入口函数的声明方式,明显是有返回值的,所以我们可以根据它来在主线程直接获取子线程的退出码


       因此我上网搜索了一下,网上基本都说可以通过在主 线程里面直接调用 GetExitCodeThread() 函数来得到子线程入口函数的退出码。

 

       GetExitCodeThread()这个函数确实可以得到子线程入口函数的退出码,但是真要使用它来得倒子线程入口函数的退出码的话是有条件的。我在网上搜多了许久,都没有具体说到这点,很零碎,最后我根据自己的实践,在结合 MSDN 上面的介绍,以及网上的一些资料,终于成功解决的这个问题。以下我就把我的总结归纳一下,以便以后查询时可以用到,同时,也希望能帮到其他同仁们!

 

  首先,GetExitCodeThread()这个函数可以直接得到由 CreateThread() 创建的子线程入口函数的退出码。以下我举个测试的例子吧!

先创建一个基于MFC的控制台工程,这样比较方便测试。这个不用我来教大家怎么创建吧,呵呵!

然后在源文件开头,可以在 main 函数外面定义一下变量:

HANDLE hThread;
DWORD errCode = 100;

同时声明子线程入口函数:

DWORD WINAPI ThreadFunc( LPVOID lpParameter );

 

接着在特定位置添加以下代码:

VC获取子线程入口函数的退出码(分别由CreateThread,_beginthread,_beginthreadex与AfxbeginThread 创建的子线程 )_第1张图片

好了,现在就是编写子线程入口函数了,代码如下:


现在代码编辑工作完成了,然我们测试一下吧,测试效果如下所以:

VC获取子线程入口函数的退出码(分别由CreateThread,_beginthread,_beginthreadex与AfxbeginThread 创建的子线程 )_第2张图片

看!效果刚刚好,正好是我们在子线程入口函数里面的退出码“8”。

 

 

 

  以上使用 CreateThread() 函数创建的子线程工作的很好,至少能达到我们想要的结果,这是否意味着使用另外三个函数,_beginthread,_beginthreadex与AfxbeginThread也能达到我们需要的效果呢?我们当然希望是,可惜的是,答案是NO,哦,不好意思,_beginthreadex应该可以,读者可以自己测试一下,可是_beginthread和AfxbeginThread创建的子线程就不能那么顺利了。为什么呢?以下我先说明一下具体的原因,然后再说明如何来解决这个问题。

   CreateThreadWindowsAPI函数,提供操作系统级别的创建线程的操作。_beginthread(_beginthreadex)AfxBeginThread的底层实现都调用了CreateThread函数。这是相似之处,但有几个区别之处是值得我们注意的。

  AfxBeginThread里面,CreateThread之后,就CloseHandle了;

  当您使用 _beginthread_endthread时,不要通过调用 Win32 APICloseHandle 显式关闭线程句柄,因为_endthread自动关闭线程句柄;

  当您使用_beginthreadex_endthreadex时,必须通过调用 Win32 APICloseHandle 关闭线程处理, _endthreadex 不关闭线程句柄

  以上这几个地方就是我们应该注意的,现在回到主题,为什么调用GetExitCodeThread()不能正常得到AfxBeginThread和 “_beginthread 与_endthread”的退出码呢,答案就在他们的底层代码自动调用CloseHandle函数。

 

以下我引用网上一段对CloseHandle()函数的介绍:

CloseHandle()

  在CreateThread成功之后会返回一个hThread的handle,且内核对象的计数加1,CloseHandle之后,引用计数减1,当变为0时,系统删除内核对象。

但是这个handle并不能完全代表这个线程,它仅仅是线程的一个“标识”,系统和用户可以利用它对相应的线程进行必要的操纵。如果在线程成功创建后,不再需要用到这个句柄,就可以在创建成功后,线程退出前直接CloseHandle掉,但这并不会影响到线程的运行。


不执行CloseHandle() 带来的后果:

  若在线程执行完之后,没有通过CloseHandle()将引用计数减1,在进程执行期间,将会造成内核对象的泄露,相当与句柄泄露,但不同于内存泄露, 这势必会对系统的效率带来一定程度上的负面影响。但是,请记住,当进程结束退出后,系统仍然会自动帮你清理这些资源。但是在这里不推荐这种做法,毕竟不是 一个良好的编程习惯!
( 应用程序运行时,有可能泄露内核对象,但是当进程终止运行时,系统能确保所有内容均被正确地清除。另外,这个情况是用于所有对象,资源和内存块,也就是说,当进程终止时,系统将保证不会留下任何对象。)

 

  呵呵,现在知道为什么了吗,啊。。。我也说一下我自己的理解吧,例如,当我们使用AfxBeginThread函数创建一个子线程时,因为等到起子线程运行退出后,该子线程对应的线程句柄也被CloseHandle()函数关闭了,导致其内核资源被系统回收了,所以我们就不能在主线程中调用GetExitCodeThread()函数来得倒子线程的退出码,因为这个函数也需要子线程的句柄作为参数,但此时子线程的内核资源已经被系统回收了,即使我们知道它的句柄也是没用的,也就是说,我们需要在调用GetExitCodeThread()函数之后,再调用CloseHandle()函数,这样才能得到我们需要的子线程函数的退出码。读者若是不信的话,可以使用我们上面使用到的例子:使用CreateThread()创建子线程的例子,把CloseHandle()放置到GetExitCodeThread()函数之前,看看还能不能得到我们想要的退出码。本人在此告诉大家,肯定不可以!呵呵!

 

  好了,现在我们终于知道为什么会这样了,也知道具体原因了,但该如何解决此问题,是不是意味着我们不能再使用GetExitCodeThread()函数来得到AfxBeginThread函数创建的子线程入口函数的退出码了呢?在这里,我跟大家说一下,其实是可以的,哈哈!下面,我就提供几种方法来给大家参考一下!

  我们可以使用以下几个函数来给子线程设置退出码:

  TerminateThread();//msdn及网上很多高手都建议不要使用该函数,再此,本人也建议大家慎用此函数,

             //想知道原因,哈哈!百度或msdn一下吧!

       ExitThread();

       AfxEndThread();

       _endthreadex();//此函数对应由_beginthreadex() 创建的子线程

       _endthread();//此函数对应由_beginthread() 创建的子线程

 

  以下我就使用AfxBeginThread函数来创建一个子线程来为大家演示一下!

  一开始还是那句话,先创建一个基于MFC的控制台项目,或是使用刚才的那个例子,本人比较懒,呵呵,所以我就在原来的那个例子上面做些改动就行啦!

 

在源文件开头定义一个变量和一个子线程入口函数:

CWinThread* thread;

UINT ThreadProc(LPVOID lpParam);

接着在main函数的相应位置创建子线程,代码如下:

VC获取子线程入口函数的退出码(分别由CreateThread,_beginthread,_beginthreadex与AfxbeginThread 创建的子线程 )_第3张图片

子线程入口函数如下:

VC获取子线程入口函数的退出码(分别由CreateThread,_beginthread,_beginthreadex与AfxbeginThread 创建的子线程 )_第4张图片

好啦,代码已经编写完成啦,接下来该干啥呢,哈哈,迫不及待了吧,那就让我们运行程序试一下咯!

VC获取子线程入口函数的退出码(分别由CreateThread,_beginthread,_beginthreadex与AfxbeginThread 创建的子线程 )_第5张图片

测试效果就如上所以啦,从中可以看出,退出码为“6”,刚好是我们在子线程入口函数里面设置的退出码!

 

  好啦,介绍了那么多,现在大家应该知道怎么来获取子线程入口函数的退出码了吧!

其实还有很多地方是需要我们注意的,比方说内存遗漏问题等,但在这里我就不多做介绍啦,相信大家都能够解决的!

 

  希望此篇文章对各位同仁有所帮助!

 

 

你可能感兴趣的:(VC,MFC,Windows)