如何结束线程?

时间:2022-04-10 22:36:16
如何从其他线程结束下面这个线程?
DWORD WINAPI ThreadProc(LPVOID param)
{
    while (b == TRUE)
    {
        xxx_func(...);
    }

    return 0;
}
本来我是用TerminateThread来结束这个线程的,但由于TerminateThread太粗暴,没有释放线程资源,从任务管理器中看到有内存泄漏。
一般地,当需要结束该线程时,设置b=FALSE即可使线程运行到while(条件)时结束循环,从而正常结束线程。但问题是由于xxx_func是一个阻塞的函数(比如accept、WaitForCommEvent等函数),所以通常这个线程停止在xxx_func处等待,运行不到while(b==TRUE)处。

18 个解决方案

#1


(1)不要用
while(b == TRUE)
应该用
while(b)

(2)既然您已经能通过b来控制ThreadProc
您的主要问题是:

xxx_func是一个阻塞的函数

因此,解决方法是:
让xxx_func每次只阻塞很短的时间。

(3)如果结束线程的行为发生在进程即将结束,
那么,您可以
<1>通过CreateThread返回的HANDLE来判断线程是否结束,
   在线程结束后,主线程再结束。
<2>通过在ThreadProc内的另外一变量来判断线程是否结束。
比如

BOOL bThreadRun = FALSE; // 线程正在运行的标志
DWORD WINAPI ThreadProc(LPVOID param)
{
    bThreadRun = TRUE;
    while (b == TRUE)
    {
        xxx_func(...);
    }

    bThreadRun = FALSE;
    return 0;
}


总之,没有办法能让线程“正常地立刻”结束,
您应该等待它结束。


#2


在xxx_func里面可以使用WaitForMultipleObjects,用一个全局的HANDLE来控制xxx_func的结束

#3


我是想寻找一个让线程"正常地立刻结束"的方法,或没有内存泄漏的"不那么正常立刻结束"的方法也可。
把xxx_func设成每次等待很短时间不好设啊。它可能等待几微秒,也可能等待几秒,也可能几个小时,说不定的。
结束线程的行为不是发生在进程即将结束,而且是可能结束了后又要再次生成新的线程,这样才有内存泄漏的问题啊,如果结束线程的行为发生在进程即将结束,那用TerminateThread也无所谓了,泄漏的内存由系统也可回收。

#4


xxx_func是accept、WaitForCommEvent之类的系统函数,不是我自已写的函数。

#5


设一个线程是否要退出的标志,阻塞函数不应无限至阻塞,应该设一个等待时间循环判断,等待的时间设短一点比如几十毫秒,这样在每次等待后判断线程退出标志
退出标志应定义为 volatile

#6


用TerminateThread()函数

#7


由主线程将退出标志设为"要退出",退出标志应该是全局变量,且应加"volatile"定义,这样就保证子线程和主线程读取和设置的是同一个变量
主线程退出前先设置该标志,然后等待一段时间让子线程退出,一段时间后若子线程仍未退出,则只能Terminate了

#8


1、使用TerminateThread()
2、使用全局变量
bool bExit;
void CTestView::OnButton1()   //启动线程 
{
         bExit = false;
FThread=CreateThread(NULL,0,thx,
(LPVOID )&x,CREATE_SUSPENDED,&dwThreadID);

ResumeThread(FThread);
}
DWORD WINAPI thx(LPVOID param)
{
while(TRUE)
{
  //...
}
if(bExit)
ExitThread(0);

}
return 0;
}
void CTestView::OnButton2() //终止线程
{
bExit = true;
}

#9


看来是没有好的方法。

期望找到一下类似于下面这样的实现方法:
void CTestView::OnButton1()   //启动线程 
{
hThread=CreateThread(NULL,0,thx,(LPVOID )&x,0,&dwThreadID);
}
DWORD WINAPI thx(LPVOID param)
{
while(TRUE)
{
    try
             {
                 xxx_func(...);
             }
             catch (...)
             {
                 ExitThread(0);
             }
}
return 0;
}
void CTestView::OnButton2() //终止线程
{
throw exception to pThread;
}

#10


我想发帖子,怎么发不了啊?

#11


最安全的办法是线程的循环体里面检查一个退出事件,此事件一触发就自己清除资源并return。  
要通知此线程退出的模块就PostThreadMessage函数,将退出事件post给该线程。  
 
hEventFinish    =    CreateEvent(NULL,TRUE,FALSE,NULL);//创建手工重置的Event对象    
 
DWORD  WINAPI  DisplayData(LPVOID  param)  
{  
           while(TRUE)  
           {  
                   if(  WaitForSingleObject(pDlg->hEventFinish,0)    ==    WAIT_OBJECT_0)      
                           return    0;                                    //让线程函数正常返回  
 
             
           //...DisplayData  
 
             
           }  
           return  0;  
}  

#12


问题是在xxx_func处阻塞了啊

#13


如果是一定要阻塞,且是无限制时间的,那就没有办法了.比如你的主线程阻塞了,而你却非要它自己退出来,这可能吗?

#14


不知你是否可以用MsgWaitForMultipleObjects,这样检测到一定的事件发生也可以退出阻塞等待

#15


if (!this->m_hThread)
return FALSE;

TRACE(_T("Killing thread %x ...\n"), m_hThreadId);

// reset the m_hEventKill which signals the thread to shutdown
VERIFY(::SetEvent(this->m_hEventKill));

// allow thread to run at higher priority during kill process
if (::WaitForSingleObject(this->m_hThread, m_dwKillingWait) == WAIT_TIMEOUT)
::TerminateThread(this->m_hThread, 0);

TRACE(_T("Thread %x killed\n"), m_hThreadId);

::ResetEvent(this->m_hEventKill);

m_bActive = FALSE;

return TRUE;

#16



DWORD WINAPI Check(LPVOID lpParameter )  // thread data
{
//DebugBreak();
COoDlg *pMonitor = (COoDlg*)lpParameter;
while(pMonitor->bStart)
{
OVERLAPPED opd;
if(NotifyAddrChange(NULL,&opd) == NO_ERROR)
{
TRACE("aaa");
}
WaitForSingleObject(pMonitor->m_hThread,5000);
}
return FALSE;
}
void COoDlg::OnOK() 
{
DWORD ThreadID;  
m_hThread = CreateThread(NULL,0,Check,this,0,&ThreadID);
if(m_hThread == NULL)
{
//AfxMessageBox("创建监控线程失败!");
return ;//FALSE;
}
else
{
bStart = true;
return ;//TRUE;
}
return ;//FALSE;

}

void COoDlg::OnCancel() 
{
bStart=0;
if(m_hThread)
{
if(::WaitForSingleObject(m_hThread,1000) == WAIT_TIMEOUT)
{
//如果超时:
TerminateThread(m_hThread,NULL);
}
CloseHandle(m_hThread);
m_hThread = NULL;
}
//CDialog::OnCancel();
}

#17


阻塞处应该总有一个超时什么的吧,可以用WaitForSingleObject设置一下超时返回,这样就可以跳出阻塞了

#18


CancelBlockingCall

#1


(1)不要用
while(b == TRUE)
应该用
while(b)

(2)既然您已经能通过b来控制ThreadProc
您的主要问题是:

xxx_func是一个阻塞的函数

因此,解决方法是:
让xxx_func每次只阻塞很短的时间。

(3)如果结束线程的行为发生在进程即将结束,
那么,您可以
<1>通过CreateThread返回的HANDLE来判断线程是否结束,
   在线程结束后,主线程再结束。
<2>通过在ThreadProc内的另外一变量来判断线程是否结束。
比如

BOOL bThreadRun = FALSE; // 线程正在运行的标志
DWORD WINAPI ThreadProc(LPVOID param)
{
    bThreadRun = TRUE;
    while (b == TRUE)
    {
        xxx_func(...);
    }

    bThreadRun = FALSE;
    return 0;
}


总之,没有办法能让线程“正常地立刻”结束,
您应该等待它结束。


#2


在xxx_func里面可以使用WaitForMultipleObjects,用一个全局的HANDLE来控制xxx_func的结束

#3


我是想寻找一个让线程"正常地立刻结束"的方法,或没有内存泄漏的"不那么正常立刻结束"的方法也可。
把xxx_func设成每次等待很短时间不好设啊。它可能等待几微秒,也可能等待几秒,也可能几个小时,说不定的。
结束线程的行为不是发生在进程即将结束,而且是可能结束了后又要再次生成新的线程,这样才有内存泄漏的问题啊,如果结束线程的行为发生在进程即将结束,那用TerminateThread也无所谓了,泄漏的内存由系统也可回收。

#4


xxx_func是accept、WaitForCommEvent之类的系统函数,不是我自已写的函数。

#5


设一个线程是否要退出的标志,阻塞函数不应无限至阻塞,应该设一个等待时间循环判断,等待的时间设短一点比如几十毫秒,这样在每次等待后判断线程退出标志
退出标志应定义为 volatile

#6


用TerminateThread()函数

#7


由主线程将退出标志设为"要退出",退出标志应该是全局变量,且应加"volatile"定义,这样就保证子线程和主线程读取和设置的是同一个变量
主线程退出前先设置该标志,然后等待一段时间让子线程退出,一段时间后若子线程仍未退出,则只能Terminate了

#8


1、使用TerminateThread()
2、使用全局变量
bool bExit;
void CTestView::OnButton1()   //启动线程 
{
         bExit = false;
FThread=CreateThread(NULL,0,thx,
(LPVOID )&x,CREATE_SUSPENDED,&dwThreadID);

ResumeThread(FThread);
}
DWORD WINAPI thx(LPVOID param)
{
while(TRUE)
{
  //...
}
if(bExit)
ExitThread(0);

}
return 0;
}
void CTestView::OnButton2() //终止线程
{
bExit = true;
}

#9


看来是没有好的方法。

期望找到一下类似于下面这样的实现方法:
void CTestView::OnButton1()   //启动线程 
{
hThread=CreateThread(NULL,0,thx,(LPVOID )&x,0,&dwThreadID);
}
DWORD WINAPI thx(LPVOID param)
{
while(TRUE)
{
    try
             {
                 xxx_func(...);
             }
             catch (...)
             {
                 ExitThread(0);
             }
}
return 0;
}
void CTestView::OnButton2() //终止线程
{
throw exception to pThread;
}

#10


我想发帖子,怎么发不了啊?

#11


最安全的办法是线程的循环体里面检查一个退出事件,此事件一触发就自己清除资源并return。  
要通知此线程退出的模块就PostThreadMessage函数,将退出事件post给该线程。  
 
hEventFinish    =    CreateEvent(NULL,TRUE,FALSE,NULL);//创建手工重置的Event对象    
 
DWORD  WINAPI  DisplayData(LPVOID  param)  
{  
           while(TRUE)  
           {  
                   if(  WaitForSingleObject(pDlg->hEventFinish,0)    ==    WAIT_OBJECT_0)      
                           return    0;                                    //让线程函数正常返回  
 
             
           //...DisplayData  
 
             
           }  
           return  0;  
}  

#12


问题是在xxx_func处阻塞了啊

#13


如果是一定要阻塞,且是无限制时间的,那就没有办法了.比如你的主线程阻塞了,而你却非要它自己退出来,这可能吗?

#14


不知你是否可以用MsgWaitForMultipleObjects,这样检测到一定的事件发生也可以退出阻塞等待

#15


if (!this->m_hThread)
return FALSE;

TRACE(_T("Killing thread %x ...\n"), m_hThreadId);

// reset the m_hEventKill which signals the thread to shutdown
VERIFY(::SetEvent(this->m_hEventKill));

// allow thread to run at higher priority during kill process
if (::WaitForSingleObject(this->m_hThread, m_dwKillingWait) == WAIT_TIMEOUT)
::TerminateThread(this->m_hThread, 0);

TRACE(_T("Thread %x killed\n"), m_hThreadId);

::ResetEvent(this->m_hEventKill);

m_bActive = FALSE;

return TRUE;

#16



DWORD WINAPI Check(LPVOID lpParameter )  // thread data
{
//DebugBreak();
COoDlg *pMonitor = (COoDlg*)lpParameter;
while(pMonitor->bStart)
{
OVERLAPPED opd;
if(NotifyAddrChange(NULL,&opd) == NO_ERROR)
{
TRACE("aaa");
}
WaitForSingleObject(pMonitor->m_hThread,5000);
}
return FALSE;
}
void COoDlg::OnOK() 
{
DWORD ThreadID;  
m_hThread = CreateThread(NULL,0,Check,this,0,&ThreadID);
if(m_hThread == NULL)
{
//AfxMessageBox("创建监控线程失败!");
return ;//FALSE;
}
else
{
bStart = true;
return ;//TRUE;
}
return ;//FALSE;

}

void COoDlg::OnCancel() 
{
bStart=0;
if(m_hThread)
{
if(::WaitForSingleObject(m_hThread,1000) == WAIT_TIMEOUT)
{
//如果超时:
TerminateThread(m_hThread,NULL);
}
CloseHandle(m_hThread);
m_hThread = NULL;
}
//CDialog::OnCancel();
}

#17


阻塞处应该总有一个超时什么的吧,可以用WaitForSingleObject设置一下超时返回,这样就可以跳出阻塞了

#18


CancelBlockingCall