The article directories

    • One, foreword
    • Second, the quotes
      • 1. Case Description
      • 2. Case realization
    • Third, problem analysis
      • A, output,
      • Second, the analysis
    • Iv. Improvement plan

One, foreword

  • This article describes a case where the main thread actively deletes child thread objects, causing the main thread to freeze (infinite wait).

Second, the quotes

1. Case Description

  • 1) The implementation includes a main thread and a child thread;
  • 2) The main thread is responsible for starting the child thread and destroying it after the child thread runs for 500ms:
  • 3) The sub-thread outputs a keepalive message every 16ms;

2. Case realization

  • Child Thread LogicThread inherits Thread (Thread class implementation reference);
#include "Thread.h"


class LogicThread : public Thread
{
public:
	LogicThread() : m_bStop(false) {}protected:
	virtual void DoWork(a) {
		while(! m_bStop) {printf("Thread[%d]: I'm active! \n", GetId());
			Sleep(16);
		}
		printf("Thread[%d]: I'm exit! \n", GetId());
	}

private:
	bool                      m_bStop;
};

int main(a) {
	LogicThread *pLS = new LogicThread;
	pLS->Start();
	Sleep(500);
	delete pLS;
	return 0;
}
Copy the code
  • Does the delete of this code run smoothly? The answer is no!

Third, problem analysis

A, output,

  • I’m active! I’m active! :
Thread[70508]: I'm active!
Thread[70508]: I'm active!
Thread[70508]: I'm active!
Thread[70508]: I'm active!
Thread[70508]: I'm active!
Thread[70508]: I'm active! .Copy the code

Second, the analysis

  • The breakthrough point of analysis is the call of DELETE;
  • If there is no delete, then the main thread can go to return 0;
  • When delete is added, the destructor of the base Thread is called, and the Stop() interface of the child Thread is called as follows:
Thread::~Thread() {
	Stop();
}

void Thread::Stop(a) {
	if(! m_pkHandle) {return;
	}
	WaitForSingleObject((HANDLE)m_pkHandle, INFINITE);
	CloseHandle((HANDLE)m_pkHandle);
	m_pkHandle = NULL;
}
Copy the code
  • Because the child thread is running and not returning, WaitForSingleObject blocks and waits. This call is made on the main thread, so the main thread is dead.

Iv. Improvement plan

  • To keep the WaitForSingleObject from waiting indefinitely, you need to ensure that the thread function exits before the logical thread is destroyed.
  • Therefore, the state of the child thread can be polled in the main thread, and the exit logic can be executed when the child thread enters the exit state.
  • To clarify the problem, add a thread termination condition, set m_bStop to true when the counter 100 is finished.
#include "Thread.h"


class LogicThread : public Thread
{
public:
	LogicThread() : m_bStop(false) {}protected:
	virtual void DoWork(a) {
		int nCnt = 100;
		while(! m_bStop) {printf("Thread[%d]: I'm active! \n", GetId());
			Sleep(16);
			if (--nCnt == 0) {
				m_bStop = true;  // Add the end condition}}printf("Thread[%d]: I'm exit! \n", GetId());
	}
private:
	bool                      m_bStop;
};

int main(a) {
	LogicThread *pLS = new LogicThread;
	pLS->Start();
	// The main thread waits for the child thread to exit;
	do {
		Sleep(16);
	} while (pLS->IsRunning());
	// Clear up thread information
	delete pLS;
	return 0;
}
Copy the code