The article directories

    • Introduction to thread API
      • Create a thread
      • 2. Restore the thread
      • 3. Wait for the semaphore
      • 4, thread status determination
      • 5. Destroy the thread
    • Second, thread class encapsulation
      • 1. Design ideas
      • 2. Header file design
      • 3. Interface implementation
      • 4. Interface analysis
    • Third, the use of thread classes
      • Thread class inheritance
      • 2. Thread class calls

Introduction to thread API

Create a thread

_beginthreadex

unsigned long _beginthreadex(
    void *security,
    unsigned stack_size,                          
    unsigned(_stdcall *start_address)(void *),    
    void *argilist, 
    unsigned initflag,
    unsigned *threaddr
);
Copy the code
Parameter names The parameter types meaning
security Void Pointers Security property. NULL indicates the default security
stack_size Unsigned integer The stack size of a thread, generally 0 by default
start_address Function addresses Void * (); void* ()
argilist Void Pointers If multiple arguments are needed, the structure pointer can be passed
initflag Unsigned integer The initial state of the new thread. 0 indicates immediate execution, CREATE_SUSPENDED indicates suspended after creation, restored by calling ResumeThread
threaddr Thread ID address Used to receive the thread ID. NULL indicates no use

The return value

  • Returns a handle to the thread if it was created successfully. If the creation fails, 0 is returned and error code errno is set. For details about error codes, see: errno Introduction.

2. Restore the thread

ResumeThread

DWORD ResumeThread( HANDLE hThread );
Copy the code
Parameter names The parameter types meaning
hThread HANDLE Handle to the thread that needs to be restored
  • If initFlag is set to CREATE_SUSPENDED when the thread is created, it indicates that the thread will not be executed immediately after being created. Therefore, ResumeThread needs to be called for thread recovery.

The return value

  • Returns the number of times the thread was suspended if the function executed successfully.
The return value why
0 The thread is not suspended
1 The thread was suspended, but has now resumed
> 1 The thread is still suspended
  • If the function fails, (DWORD) -1 is returned. The error code is obtained from the GetLastError function.

3. Wait for the semaphore

WaitForSingleObject

DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );
Copy the code
Parameter names The parameter types meaning
hHandle HANDLE Handles to waiting signals, not just thread handles, but to semaphore, process, event, console input, and so on
dwMilliseconds DWORD Timeout. If this parameter is INFINITE, the timeout is ignored

The return value

  • This is a blocking function that does not return if the thread is still executing;

4, thread status determination

GetExitCodeThread

BOOL GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode );
Copy the code
Parameter names The parameter types meaning
hThread HANDLE The handle to the thread that needs to get the exit status
lpExitCode LPDWORD The address is passed to receive the thread exit status

The return value

  • A non-blocking function that returns immediately after being called;
  • If the specified thread is not terminated and the function returns success, the status is STILL_ACTIVE; STILL_ACTIVE: STILL_ACTIVE: STILL_ACTIVE: STILL_ACTIVE: STILL_ACTIVE: STILL_ACTIVE: STILL_ACTIVE: STILL_ACTIVE: STILL_ACTIVE

5. Destroy the thread

CloseHandle

BOOL CloseHandle( HANDLE hObject );
Copy the code
Parameter names The parameter types meaning
hObject HANDLE Handle to the thread that needs to be closed

Second, thread class encapsulation

1. Design ideas

  • 1) Provide a thread class for inheritance to achieve polymorphism;
  • 2) The destructor of thread class is defined as virtual to avoid memory leakage;
  • 3) Interface design: thread starting, thread termination, thread survival determination, thread working content;
  • 4) The work of a thread is what the class that inherits it needs to do, so it needs to be designed as a virtual function;

2. Header file design

Thread.h

#include <windows.h>
#include <process.h>

class Thread
{
public:
	Thread();
	virtual ~Thread();
	bool            Start(a);
	void            Stop(a);
	bool            IsRunning(a) const;
	unsigned int	GetId(a);
protected:
	virtual void    DoWork(a) {}
private:
	static unsigned WINAPI ThreadProc(void* pvDerivedThread);
	void*    m_pkHandle;
	string   m_kName;
	unsigned int m_Id;
};
Copy the code

3. Interface implementation

Thread.cpp

#include "Thread.h"
Thread::Thread(): m_pkHandle(0), m_Id(0) {
}

Thread::~Thread() {
	Stop();
}
unsigned WINAPI Thread::ThreadProc(void* pvDerivedThread) {
	Thread* pThread = (Thread*)pvDerivedThread;
	if (pThread) {
		pThread->DoWork();
	}
	return 0;
}
bool Thread::Start(a) {
	if (m_pkHandle || this->IsRunning()) {
		return false;
	}
	m_pkHandle = (HANDLE)_beginthreadex(NULL.0, &ThreadProc, this.0, &m_Id);
	returnm_pkHandle ! =NULL;
}
void Thread::Stop(a) {
	if(! m_pkHandle) {return;
	}
	WaitForSingleObject((HANDLE)m_pkHandle, INFINITE);
	CloseHandle((HANDLE)m_pkHandle);
	m_pkHandle = NULL;
}
bool Thread::IsRunning(a) const {
	if (m_pkHandle) {
		DWORD exitCode = 0;
		if (GetExitCodeThread((HANDLE)m_pkHandle, &exitCode)) {
			if (STILL_ACTIVE == exitCode) {
				return true; }}}return false;
}
unsigned int Thread::GetId(a) {
	return m_Id;
}
Copy the code

4. Interface analysis

  • 1) Call Stop when the thread class is destructed to ensure that the thread can end smoothly;
  • 2) ThreadProc is a static function that can be used to pass arguments to callback functions.
  • 3) Start() is the function that actually creates the thread. After the thread is created, DoWork starts.
  • 4) Stop() is the function that actually terminates the thread. Before terminating the thread, call WaitForSingleObject to ensure that the thread’s callback ThreadProc has returned.
  • 5) IsRunning() is used to determine whether ThreadProc has returned successfully. Stop() is called only when false is returned.

Third, the use of thread classes

Thread class inheritance

  • Implement a thread class that outputs a countdown of 3,2,1 and then terminates the thread itself;
class LogicService : public Thread
{
public:
	LogicService() : m_bStop(false) {}void setIndentation(int ind) {
		m_iIndentation = ind;
	}
protected:

	virtual void DoWork(a) {
		int iStopCount = 3;
		while(! m_bStop) {// To differentiate each thread, use a different indentation
			for (int i = 0; i < m_iIndentation; ++i) {
				printf("");
			}
			printf("Thread(%d) %d Count down! \n", GetId(), iStopCount);
			Sleep(10);
			--iStopCount;
			if (iStopCount == 0) {
				m_bStop = true; }}printf("Thread(%d) exit! \n", GetId());
	}

private:
	bool m_bStop;
	int m_iIndentation;
};
Copy the code

2. Thread class calls

#define MAXT 4

int main(a) {
	LogicService *pLS = new LogicService[MAXT];
	if (pLS)
	{
		for (int i = 0; i < MAXT; ++i)
		{
			pLS[i].setIndentation(i);
			pLS[i].Start();
		}
	}
	Sleep(100);
	delete [] pLS;

	return 0;
}
Copy the code
  • In order to distinguish each thread, use different indentation output for easy viewing;
  • The output is as follows:
Thread(154472) 3 Count down!
        Thread(154256) 3 Count down!
                        Thread(153952) 3 Count down!
                Thread(154252) 3 Count down!
Thread(154472) 2 Count down!
                        Thread(153952) 2 Count down!
        Thread(154256) 2 Count down!
                Thread(154252) 2 Count down!
Thread(154472) 1 Count down!
        Thread(154256) 1 Count down!
                        Thread(153952) 1 Count down!
                Thread(154252) 1 Count down!
Thread(154472) exit!
Thread(154252) exit!
Thread(153952) exit!
Thread(154256) exit!
Copy the code