C++ 多线程 API 简介

一、线程 API 介绍

1、创建线程

_beginthreadex

unsigned long _beginthreadex(
    void *security,
    unsigned stack_size,                          
    unsigned(_stdcall *start_address)(void *),    
    void *argilist, 
    unsigned initflag,
    unsigned *threaddr
);
参数名 参数类型 含义
security void指针 安全属性, 为NULL时表示默认安全性
stack_size 无符号整型 线程的堆栈大小, 一般默认为0
start_address 函数地址 线程回调函数,参数类型为 void*,传 NULL 会有异常抛出
argilist void指针 线程回调函数的参数,需要多个参数的时候传递结构体指针即可
initflag 无符号整型 新线程的初始状态,0表示立即执行,CREATE_SUSPENDED 表示创建之后挂起,调用 ResumeThread 恢复
threaddr 线程ID地址 用来接收线程ID,传 NULL 表示不使用

返回值

  • 如果线程创建成功,返回一个该线程的句柄;如果创建失败,返回 0,并且置错误码 errno,错误码相关的可以参考:errno 简介

2、恢复线程

ResumeThread

DWORD ResumeThread(
  HANDLE hThread
);
参数名 参数类型 含义
hThread HANDLE 需要恢复的线程句柄
  • 如果在创建线程的时候,initflag 置上了标志位 CREATE_SUSPENDED,则代表线程创建后不会立即执行,需要调用 ResumeThread 进行线程恢复;

返回值

  • 如果函数执行成功,则返回线程被挂起的次数;
返回值 原因
0 线程没有被挂起
1 线程曾经被挂起,但是现在已经恢复
>1 线程还是处于挂起状态
  • 如果函数执行失败,则返回 (DWORD) -1,具体错误码,通过 GetLastError 函数获取;

3、等待信号量

WaitForSingleObject

DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD  dwMilliseconds
);
参数名 参数类型 含义
hHandle HANDLE 等待信号的句柄,不仅仅是线程句柄,还可以是 信号量、进程、事件、控制台输入 等其它对象的句柄等等
dwMilliseconds DWORD 超时时间,如果这个参数是 INFINITE ,则忽略超时时间

返回值

  • 这是一个阻塞函数,如果线程还在执行,这里是不会返回的;

4、线程状态判定

GetExitCodeThread

BOOL GetExitCodeThread(
  HANDLE  hThread,
  LPDWORD lpExitCode
);
参数名 参数类型 含义
hThread HANDLE 需要获得退出状态的线程句柄
lpExitCode LPDWORD 传的是地址,用来接收线程退出状态

返回值

  • 非阻塞函数,调用后立即返回;
  • 如果指定的线程没有结束并且函数返回成功,状态返回 STILL_ACTIVE;这个函数只有当线程结束后才会返回合法的退出码,所以 STILL_ACTIVE 不能作为一个合法的退出码;

5、销毁线程

CloseHandle

BOOL CloseHandle(
  HANDLE hObject
);
参数名 参数类型 含义
hObject HANDLE 需要关闭的线程句柄

二、线程类的封装

1、设计思路

  • 1)提供一个线程类供继承,实现多态;
  • 2)线程类的析构函数定义成 virtual,避免内存泄漏;
  • 3)接口设计:线程启动、线程终止、线程存活判定、线程工作内容;
  • 4)线程工作内容是继承它的类需要做的事情,所以需要设计成虚函数;

2、头文件设计

Thread.h

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

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

3、接口实现

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() {
    
    
	if (m_pkHandle || this->IsRunning()) {
    
    
		return false;
	}
	m_pkHandle = (HANDLE)_beginthreadex(NULL, 0, &ThreadProc, this, 0, &m_Id);
	return m_pkHandle != NULL;
}
void Thread::Stop() {
    
    
	if (!m_pkHandle) {
    
    
		return;
	}
	WaitForSingleObject((HANDLE)m_pkHandle, INFINITE);
	CloseHandle((HANDLE)m_pkHandle);
	m_pkHandle = NULL;
}
bool Thread::IsRunning() 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() {
    
    
	return m_Id;
}

4、接口分析

  • 1)线程类析构的时候调用 Stop,确保线程能够顺利结束;
  • 2)ThreadProc 作为类静态函数,方便实现线程回调函数的传参;
  • 3)Start() 为实际创建线程的函数,创建线程后,DoWork 就开始工作了;
  • 4)Stop() 为实际结束线程的函数,结束线程前需要调用 WaitForSingleObject 确保线程的回调函数 ThreadProc 已经返回了;
  • 5)IsRunning() 用来判断线程回调函数 ThreadProc 是否已经顺利返回,当返回 false 的时候,才能去调用 Stop();

三、线程类的使用

1、线程类继承

  • 实现一个线程类,要求输出倒计时3,2,1,然后自行结束线程;
class LogicService : public Thread
{
    
    
public:
	LogicService() : m_bStop(false) {
    
    

	}
	void setIndentation(int ind) {
    
    
		m_iIndentation = ind;
	}
protected:

	virtual void DoWork() {
    
    
		int iStopCount = 3;
		while (!m_bStop) {
    
    
			// 为了区别每条线程,用不同的缩进
			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;
};

2、线程类调用

#define MAXT 4

int main() {
    
    
	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;
}
  • 为了区别每条线程,用不同的缩进进行输出方便观看;
  • 输出如下:
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!

猜你喜欢

转载自blog.csdn.net/WhereIsHeroFrom/article/details/108912618