VC线程安全退出的方法

来源:互联网 发布:win10修改电脑mac地址 编辑:程序博客网 时间:2024/05/22 08:21

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


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 更换网络后无线路由器不能用怎么办 手机登录不了路由器登录业面怎么办 海康威视通道用户被锁定怎么办 无线适配器或访问点有问题怎么办 客户买鞋子说价格贵该怎么办 小米5s刷成真砖后怎么办 手机电源键坏了开不了机怎么办 手机开关键坏了开不了机怎么办 vivo手机解屏密码忘了怎么办 小米max关机后开关键坏了怎么办 联想手机刷机失败无限重启怎么办 红米2a显示白屏怎么办 小米6手机一直处于开机状态怎么办 怎么在手机上看wifi密码怎么办 怎么查自己的宽带密码忘记了怎么办 怎么查自己宽带账号密码忘了怎么办 电脑重置路由器密码连不上网怎么办 e盘和f盘没有了怎么办 复制文件过程中自己卡住了怎么办 电脑卡住了怎么办 鼠标也点不动 善领wifi连上网不能用怎么办 苹果手机软件更新后网速太慢怎么办 装了固态硬盘开机还慢怎么办 华为荣耀8青春版玩游戏卡怎么办 光猫自带wifi网络很差怎么办 侠盗猎车手自由城之章卡退怎么办? 夏天带头盔晃眼睛太厉害怎么办 别人把钱误转我卡上我怎么办? 家里预留的的网线太短怎么办 电信路由器坏了网线接口断了怎么办 数据线充手机的接头处断了怎么办 新买的小米手环充不进去电怎么办 绝地求生手游被队友故意炸死怎么办 一加3t屏幕开了怎么办? 孕妇吃了8个杏怎么办啊 洗碗盆落水器垫子密封不好怎么办? 手剥橙子剥的特别疼怎么办? 经常带对讲机的耳麦耳朵痛怎么办 公安检查遇到穿便装的军人怎么办 cf幽灵鬼呼吸辅军训刘海怎么办助 眼睛被等离子切割器的光烤了怎么办