VC线程安全退出的方法

1. 如果创建的线程属于阻塞类型的,比如线程函数中有套接字recv、sendto类似的操作,可能会死等着接收数据,这时想要退出该线程,只能用:

BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode ),强行终止该线程。

事实上,也没有好办法了,因为该线程的while循环不“转”了!


2. 如果创建的线程内while循环能够正常的在“转动”,应该使用下面方法:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. bool g_bExit = false;  
  2.   
  3. //测试是否安全退出的指针  
  4. unsigned char *buf = NULL;  
  5.   
  6. UINT MyControllingFunction( LPVOID pParam )  
  7. {  
  8.     while(1)  
  9.     {  
  10.         static int k = 0;  
  11.         printf("线程内操作: %d\n", k++);  
  12.         Sleep(2000);  
  13.         if(g_bExit)  
  14.             break;  
  15.     }  
  16.   
  17.     free(buf);  
  18.     buf = NULL;  
  19.     return 1L;  
  20. }  
  21.   
  22.   
  23. using namespace std;  
  24.   
  25. int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])  
  26. {  
  27.     int nRetCode = 0;  
  28.   
  29.     // initialize MFC and print and error on failure  
  30.     if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))  
  31.     {  
  32.         // TODO: change error code to suit your needs  
  33.         cerr << _T("Fatal Error: MFC initialization failed") << endl;  
  34.         nRetCode = 1;  
  35.     }  
  36.     else  
  37.     {  
  38.         //创建一个线程  
  39.         CWinThread *pThread = AfxBeginThread(MyControllingFunction, NULL);  
  40.           
  41.         //随便分配一块内存区域  
  42.         buf = (unsigned char *)malloc(1024);  
  43.           
  44.         //主线程  
  45.         while(1)  
  46.         {  
  47.             if(kbhit())  
  48.             {  
  49.                 char ch = getch();  
  50.                 if(ch == 27)//ESC  
  51.                 {  
  52.                     printf("主线程退出\n");  
  53.                     g_bExit = true;  
  54.                     break;  
  55.                 }  
  56.             }  
  57.         }  
  58.       
  59.         //一直等待创建的线程完全退出  
  60.         ::WaitForSingleObject(pThread->m_hThread, INFINITE);  
  61.     }  
  62.   
  63.     return nRetCode;  
  64. }  

上述代码段的用意是:① 借助一个全局变量通知被创建的线程循环break后退出;② 在主线程使用WaitForSingleObject等待线程结束。

上述代码段的buf动态内存是模拟了在创建的线程,如果完全退出时,buf会被free释放掉,反之buf会内存泄露。可以注释掉WaitForSingleObject来验证buf是否存在内存泄露。


线程内Sleep两秒的用意,该线程不是一个完全阻塞线程,但又不是“转动”很快的线程。当主线程的while循环退出后,能观察到::WaitForSingleObject的作用。



附:

WaitForSingleObject函数的使用

等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止。

 

WaitForSingleObject 函数

DWORD WaitForSingleObject(

HANDLE hObject,

     DWORD dwMilliseconds

);

第一个参数hObject标识一个能够支持被通知/未通知的内核对象(前面列出的任何一种对象都适用)。

第二个参数dwMilliseconds允许该线程指明,为了等待该对象变为已通知状态,它将等待多长时间。(INFINITE无限时间量,INFINITE已经定义为0xFFFFFFFF(或-1))

传递INFINITE有些危险如果对象永远变为已通知状态,那么调用线程永远不会被唤醒,它将永远处于死锁状态,不过,它不会浪费宝贵的C P U时间。

 

例子:

DWORD dw = WaitForSingleObject(hProcess, 5000);

switch(dw)

{

   case WAIT_OBJECT_0:

      // The process terminated.

      break;

 

   case WAIT_TIMEOUT:

      // The process did not terminate within 5000 milliseconds.

      break;

 

   case WAIT_FAILED:

      // Bad call to function (invalid handle?)

      break;

}

上面这个代码告诉系统,在特定的进程(hProcess终止运行(进程hProcess终止运行变成已经通知)之前,或者在5000m s时间结束之前,调用线程不应该变为可调度状态。

 WaitForSingleObject的返回值能够指明调用线程为什么再次变为可调度状态。

如果线程等待的对象变为已通知状态,那么返回值是WAIT_OBJECT_0

如果设置的超时已经到期,则返回值是WAIT_TIMEOUT

如果将一个错误的值(如一个无效句柄)传递给WaitForSingleObject,那么返回值将是WAIT_FAILED(若要了解详细信息,可调用GetLastError)。

 

WaitForMultipleObjects函数

WaitForMultipleObjects函数与WaitForSingleObject函数很相似,区别在于它允许调用线程同时查看若干个内核对象的已通知状态:

DWORD WaitForMultipleObjects(

DWORD dwCount,

   CONST HANDLE* phObjects,

   BOOL fWaitAll,

   DWORD dwMilliseconds

);

dwCount参数用于指明想要让函数查看的内核对象的数量。这个值必须1MAXIMU M_WAIT_OBJECTS(在Windows头文件中定义为64)之间。

phObjects参数是指向内核对象句柄的数组的指针。

 

可以以两种不同的方式来使用WaitForMultipleObjects函数

一种方式是让线程进入等待状态,直到指定内核对象中的任何一个变为已通知状态。

另一种方式是让线程进入等待状态,直到所有指定的内核对象都变为已通知状态。

fWaitAll参数告诉该函数,你想要让它使用何种方式。如果为该参数传递TRUE,那么在所有对象变为已通知状态之前,该函数将不允许调用线程运行。

dwMilliseconds参数的作用与它在WaitForSingleObject中的作用完全相同。如果在等待的时候规定的时间到了,那么该函数无论如何都会返回。。

WaitForMultipleObjects函数的返回值告诉调用线程,为什么它会被重新调度。可能的返回值是WAIT_FAILEDWAIT_TIMEOUT。如果为fWaitAl l参数传递TRUE,同时所有对象均变为已通知状态,那么返回值是WAIT_OBJECT_0。如果为fWaitAll传递FALSE,那么一旦任何一个对象变为已通知状态,该函数便返回。在这种情况下,你可能想要知道哪个对象变为已通知状态。返回值是WAIT_OBJECT_0与(WAIT_OJECT_0 + dwCount-1之间的一个值。换句话说,如果返回值不是WAIT_TIMEOUT,也不是WAIT_FAILED,那么应该从返回值中减去WAIT_OBJECT_0。产生的数字是作为第二个参数传递给WaitForMultipleObjects的句柄数组中的索引。该索引说明哪个对象变为已通知状态。

 

下面是说明这一情况的一些示例代码

HANDLE h[3];

h[0] = hProcess1;

h[1] = hProcess2;

h[2] = hProcess3;

DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000);

switch(dw)

{

   case WAIT_FAILED:

      // Bad call to function (invalid handle?)

      break;

 

   case WAIT_TIMEOUT:

      // None of the objects became signaled within 5000 milliseconds.

      break;

 

   case WAIT_OBJECT_0 + 0:

      // The process identified by h[0] (hProcess1) terminated.

      break;

 

   case WAIT_OBJECT_0 + 1:

      // The process identified by h[1] (hProcess2) terminated.

      break;

 

   case WAIT_OBJECT_0 + 2:

      // The process identified by h[2] (hProcess3) terminated.

      break;

}

转自http://www.cnblogs.com/fangyukuan/archive/2010/09/03/1817095.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值