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;
}