问一下各位老师关于mfc线程的问题

m0_37580103 2018-08-06 02:58:27
我在我的工程项目中添加了一个“启动线程”按钮,用来开启线程,其函数为,还有一个“退出线程”按钮,其函数为,线程部分函数主要是一个while死循环用来实时监听总线上传输的数据信息,当点击“退出线程”时,如下所示标志位为真,退出死循环。
当我点击“启动按钮”时,总线信息采集正常,点击“退出线程”时,也正常工作。。。。问题来了,当我再次点击“启动线程时,就不能正常启动线程了,没办法不停监听总线信息了,,这是怎么回事呢,请教一下各位老师,十分感谢
...全文
113 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
m0_37580103 2018-08-06
  • 打赏
  • 举报
回复
十分感谢各位老师,问题解决了
worldy 2018-08-06
  • 打赏
  • 举报
回复
使用一个信号来退出线程,不要使用TerminateThread暴力退出。简单点,使用一个全局变量,复杂点使用事件对象


while(~bEndThread)
{
...........................
}

主线程通过控制bEndThread变量,退出
schlafenhamster 2018-08-06
  • 打赏
  • 举报
回复
工作者(worker)线程 例子:

//
// The CommThread Function.
//
UINT CSerialPort::CommThread(LPVOID pParam)
{
// Cast the void pointer passed to the thread back to
// a pointer of CSerialPort class
CSerialPort *port = (CSerialPort*)pParam;

// Set the status variable in the dialog class to
// TRUE to indicate the thread is running.
port->m_bThreadAlive = TRUE;

// Misc. variables
DWORD BytesTransfered = 0;
DWORD Event = 0;
DWORD CommEvent = 0;
DWORD dwError = 0;
COMSTAT comstat;
BOOL bResult = TRUE;

// Clear comm buffers at startup
if (port->m_hComm) // check if the port is opened
PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

// begin forever loop. This loop will run as long as the thread is alive.
for (;;)
{

// Make a call to WaitCommEvent(). This call will return immediatly
// because our port was created as an async port (FILE_FLAG_OVERLAPPED
// and an m_OverlappedStructerlapped structure specified). This call will cause the
// m_OverlappedStructerlapped element m_OverlappedStruct.hEvent, which is part of the m_hEventArray to
// be placed in a non-signeled state if there are no bytes available to be read,
// or to a signeled state if there are bytes available. If this event handle
// is set to the non-signeled state, it will be set to signeled when a
// character arrives at the port.

// we do this for each port!

bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);

if (!bResult)
{
// If WaitCommEvent() returns FALSE, process the last error to determin
// the reason..
switch (dwError = GetLastError())
{
case ERROR_IO_PENDING:
{
// This is a normal return value if there are no bytes
// to read at the port.
// Do nothing and continue
break;
}
case 87:
{
// Under Windows NT, this value is returned for some reason.
// I have not investigated why, but it is also a valid reply
// Also do nothing and continue.
break;
}
default:
{
// All other error codes indicate a serious error has
// occured. Process this error.
port->ProcessErrorMessage("WaitCommEvent()");
break;
}
}
}
else
{
// If WaitCommEvent() returns TRUE, check to be sure there are
// actually bytes in the buffer to read.
//
// If you are reading more than one byte at a time from the buffer
// (which this program does not do) you will have the situation occur
// where the first byte to arrive will cause the WaitForMultipleObjects()
// function to stop waiting. The WaitForMultipleObjects() function
// resets the event handle in m_OverlappedStruct.hEvent to the non-signelead state
// as it returns.
//
// If in the time between the reset of this event and the call to
// ReadFile() more bytes arrive, the m_OverlappedStruct.hEvent handle will be set again
// to the signeled state. When the call to ReadFile() occurs, it will
// read all of the bytes from the buffer, and the program will
// loop back around to WaitCommEvent().
//
// At this point you will be in the situation where m_OverlappedStruct.hEvent is set,
// but there are no bytes available to read. If you proceed and call
// ReadFile(), it will return immediatly due to the async port setup, but
// GetOverlappedResults() will not return until the next character arrives.
//
// It is not desirable for the GetOverlappedResults() function to be in
// this state. The thread shutdown event (event 0) and the WriteFile()
// event (Event2) will not work if the thread is blocked by GetOverlappedResults().
//
// The solution to this is to check the buffer with a call to ClearCommError().
// This call will reset the event handle, and if there are no bytes to read
// we can loop back through WaitCommEvent() again, then proceed.
// If there are really bytes to read, do nothing and proceed.

bResult = ClearCommError(port->m_hComm, &dwError, &comstat);

if (comstat.cbInQue == 0)
continue;
} // end if bResult

// Main wait function. This function will normally block the thread
// until one of nine? events occur that require action.
Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);

switch (Event)
{
case 0:
{
// Shutdown event. This is event zero so it will be
// the higest priority and be serviced first.

port->m_bThreadAlive = FALSE;

// Kill this thread. break is not needed, but makes me feel better.
AfxEndThread(100);
break;
}
case 1: // read event
{
GetCommMask(port->m_hComm, &CommEvent);
if (CommEvent & EV_CTS)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
if (CommEvent & EV_RXFLAG)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
if (CommEvent & EV_BREAK)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
if (CommEvent & EV_ERR)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
if (CommEvent & EV_RING)
::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);

if (CommEvent & EV_RXCHAR)
// Receive character event from port.
ReceiveChar(port, comstat);

break;
}
case 2: // write event
{
// Write character event from port
WriteChar(port);
break;
}

} // end switch

} // close forever loop

return 0;
}

//
// start comm watching
//
BOOL CSerialPort::StartMonitoring()
{
if (!(m_Thread = AfxBeginThread(CommThread, this)))
return FALSE;
TRACE("Thread started\n");
return TRUE;
}
m0_37580103 2018-08-06
  • 打赏
  • 举报
回复
引用 5 楼 schlafenhamster 的回复:
推荐
AfxBeginThread
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
不太明白您的意思,能说详细一些吗,老师。。
m0_37580103 2018-08-06
  • 打赏
  • 举报
回复
引用 6 楼 zhao4zhong1 的回复:
你代码中已经用bext1作为线程退出标志了。
老师按您的方法试了一下,好像不行,不知道什么原因。。
赵4老师 2018-08-06
  • 打赏
  • 举报
回复
你代码中已经用bext1作为线程退出标志了。
schlafenhamster 2018-08-06
  • 打赏
  • 举报
回复
推荐
AfxBeginThread
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

m0_37580103 2018-08-06
  • 打赏
  • 举报
回复
引用 1 楼 zhao4zhong1 的回复:
一般不用TerminateThread退出线程。
把调用TerminateThread的那句注释掉。
,那老师我退出线程是直接用标志位呢,还是换一个用于退出线程的API函数呢?
schlafenhamster 2018-08-06
  • 打赏
  • 举报
回复
Remarks
TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code and its initial stack is not deallocated. DLLs attached to the thread are not notified that the thread is terminating.

TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:

If the target thread owns a critical section, the critical section will not be released.
If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
A thread cannot protect itself against TerminateThread, other than by controlling access to its handles. The thread handle returned by the CreateThread and CreateProcess functions has THREAD_TERMINATE access, so any caller holding one of these handles can terminate your thread.

m0_37580103 2018-08-06
  • 打赏
  • 举报
回复
引用 2 楼 schlafenhamster 的回复:
Remarks
TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code and its initial stack is not deallocated. DLLs attached to the thread are not notified that the thread is terminating.

TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:

If the target thread owns a critical section, the critical section will not be released.
If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
A thread cannot protect itself against TerminateThread, other than by controlling access to its handles. The thread handle returned by the CreateThread and CreateProcess functions has THREAD_TERMINATE access, so any caller holding one of these handles can terminate your thread.
老师如果不用TerminateThread函数,应该怎么办呢。。
赵4老师 2018-08-06
  • 打赏
  • 举报
回复
一般不用TerminateThread退出线程。
把调用TerminateThread的那句注释掉。

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧