【C++】多线程之CreateThread

WIN32API,需要包含头文件windows.h

API简介

简单了解下,平时用到的也就那两三个。

接口简介
SwitchToThread切换到另一个可调度线程
CreateThread创建线程
CreateRemoteThread创建远程线程
GetCurrentThread获取线程句柄
GetCurrentThreadId获取线程ID
OpenThread打开一个现有线程对象
SetThreadPriority设置线程优先级
GetThreadPriority获取线程优先级
SetThreadPriorityBoost设置开关–系统动态提升该线程的优先级
GetThreadPriorityBoost获取~开关
ExitThread在线程的执行过程中终止
TerminateThread在线程的外面终止
GetExitCodeThread获取一个已中止线程的退出代码
SuspendThread暂停线程
ResumeThread恢复线程
SetThreadStackGuarantee要求系统在抛出EXCEPTION_STACK_OVERFLOW异常的时候,保证仍然有指定大小的空闲区可以用
WaitForSingleObject阻塞,直到等到信号
CloseHandle关闭句柄

CreateThread导致内存泄漏?

根据百度来的,口水一下。C运行库中有许多全局变量,如错误码等。多个线程同时操作这些全局变量,就会出错(没同步)。为了解决未同步问题,微软想出了个办法,就是给每个线程划分了自己存全局变量的空间,TLS(thread local storage)。这样,各用各的,就不会出错了。奇怪的是,CreateThread压根没TLS的概念,就不会创建这个内存。当在CreateThread创建的线程中要读写那些全局变量时,发现没有TLS,就会创建一个给自己用。可恨的是,CloseHandle中不会释放TLS。这样,内存就泄漏了。所以,为了保险起见,创建线程使用C运行库中的_beginthreadex。

测试,通过监视程序内存,确实发现内存缓慢增长。

DWORD g_id = 0;

DWORD WINAPI fun1(void* param)
{
	int i = errno; //使用C运行时变量
	Sleep(20); //确保线程返回有效句柄

	//_endthreadex(g_id); //即使加上这句也会内存泄漏
	return 0;
}


int main()
{
	while (1)
	{
		HANDLE handle = CreateThread(nullptr, 0, &fun1, nullptr, THREAD_RESUME, &g_id);
		WaitForSingleObject(handle, INFINITE);	//等当前线程自然结束
		CloseHandle(handle);
	}

    return 0;
}

SuspendThread的计数规则

在测试中,对一个线程连续SuspendThread三次,然后ResumeThread一次,发现线程没有被唤醒。直到再ResumeThread两次后,线程才被唤醒。估计线程内有个计数,SuspendThread一次加一,ResumeThread一次减一。0表示线程可以执行啦,求CPU来拥抱。

自定义一个实用的线程类

一个理想的线程,当然是希望它自然退出,不能自然退出视为逻辑BUG。同时,能控制线程运行,挂起,唤醒和结束。至于优先级之类的,貌似手动设置不如系统优化。

公有方法

	//启动,线程初始状态为暂停。
	bool play();
	//暂停,同一线程,最多被SuspendThread一次。
	bool pause();
	//结束,若是暂停状态,先启动再让其自然退出。
	bool stop();
	//当前状态,启动|暂停|结束
	eState getState();

完整源码(也可下载完整测试工程)

.h

#pragma once

typedef void(*proc_type)(void*);

class ThreadWin
{
public:
	enum eState { PLAY = 1, PAUSE, STOP };

	friend unsigned __stdcall threadWinProc(void* param);

	ThreadWin(proc_type proc, void* param);
	~ThreadWin();

	//启动
	bool play();
	//暂停
	bool pause();
	//结束
	bool stop();
	//当前状态
	eState getState();

private:
	//禁止拷贝
	ThreadWin(const ThreadWin &) = delete;
	//禁止赋值
	ThreadWin& operator=(const ThreadWin &) = delete;

private:
	proc_type	m_proc;		//线程执行函数
	void*		m_param;	//执行函数参数
	eState		m_state;	//线程状态
	unsigned	m_handle;	//线程句柄
	unsigned	m_id;	 	//线程ID
};

.cpp

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

static unsigned __stdcall threadWinProc(void* param)
{
	ThreadWin* th = (ThreadWin*)param;

	while (ThreadWin::STOP != th->m_state)
	{
		th->m_proc(th->m_param);
	}

	return 0;
}

ThreadWin::ThreadWin(proc_type proc, void* param)
	: m_proc(proc)
	, m_param(param)
	, m_state(PAUSE)
{
	//err: 0
	m_handle = _beginthreadex(NULL, 0, threadWinProc, this, CREATE_SUSPENDED, &m_id);
}

ThreadWin::~ThreadWin()
{
	stop();
}

bool ThreadWin::play()
{
	if (0 == m_handle || STOP == m_state)
	{
		return false;
	}

	DWORD ret = ResumeThread((HANDLE)m_handle);
	if (-1 == ret)
	{
		return false;
	}

	m_state = PLAY;
	return true;
}

bool ThreadWin::pause()
{
	if (0 == m_handle || STOP == m_state)
	{
		return false;
	}

	if (PAUSE == m_state)
	{
		return true;
	}

	DWORD ret = SuspendThread((HANDLE)m_handle);
	if (-1 == ret)
	{
		return false;
	}

	m_state = PAUSE;
	return true;
}

bool ThreadWin::stop()
{
	if (0 == m_handle)
	{
		return false;
	}

	if (PAUSE == m_state)
	{
		bool ret = play();
		if (!ret)
		{
			return false;
		}
	}

	m_state = STOP;
	WaitForSingleObject((HANDLE)m_handle, INFINITE);
	CloseHandle((HANDLE)m_handle);
	m_handle = 0;

	return true;
}

ThreadWin::eState ThreadWin::getState()
{
	return m_state;
}
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值