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