DWORD = unsigned long
HANDLE = void *
LPVOID = void *
WINAPI = __stdcall
//线程函数的原型
DWORD WINAPI ThreadFunc(LPVOID);
//创建线程:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
//安全属性,一般为NULL
SIZE_T dwStackSize,
//栈大小,0表示缺省大小1M
LPTHREAD_START_ROUTINE lpStartAddress,
//函数指针
LPVOID lpParameter,
//函数的参数
DWORD dwCreationFlags,
//线程标志,0表示立即激活
LPDWORD lpThreadId
//保存线程的id号
);
#include <process.h>
uintptr_t __cdecl _beginthreadex(void * _Sequrity,
unsigned int _StackSize,
unsigned int (__stdcall *_StartAddress)(void*),
void * _ArgList,
unsigned int _InitFlag,
unsigned int * _ThrdAddr);
//C运行库创建线程函数
//关闭核心对象
BOOL CloseHandle(HANDLE hObject);//除非对内核对象的所有引用都已关闭,否则该对象不会实际删除
线程对象的默认引用计数是2。
当你调用CloseHandle( )时,引用计数下降1,当线程结束时,引用计数再降1。
只有当两件事情都发生了(不管顺序如何)的时候,这个对象才会被真正清除。
//核心对象包括:
进程(processes)
线程(threads)
文件(files)
事件(events)
信号量(semaphores)
互斥器(mutexes)
管道(Pipes:分为named 和anonymous 两种)
//获取线程退出代码
BOOL GetExitCodeThread(HANDLE hThread, LPVOID IpExitCode);
如果线程还未结束,IpExitCode存储的是 STILL_ACTIVE,函数返回的仍然是true。
//结束线程
1. void ExitThread(DWORD dwExitCode);
该函数将终止线程的运行,并导致操作系统清除该线程使用的所有操作系统资源。但是,C++资源(如C++类对象)将不被撤消。
所以最好从线程函数返回,而不是通过调用ExitThread来返回。
2. BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode);//结束指定的线程,这个最好不用
3. #include <process.h>
void _endthread(void);
void _endthreadex(void);
_endthread 自动关闭线程句柄。因此,当使用 _beginthread 和 _endthread时,不要通过调用 Win32 API CloseHandle 显式关闭线程句柄。
_endthreadex 不关闭线程句柄。 因此,当使用 _beginthreadex 和 _endthreadex时,必须通过调用 Win32 API CloseHandle 关闭线程处理。
这两个函数同样不调用对象的析构函数。
//获得错误编号
DWORD GetLastError(void);
//等待一个对象
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMiliseconds);
等待指定对象若干毫秒。0毫秒表示立刻返回,INFINITE(-1)表示阻塞。
返回值:
WAIT_OBJECT_0 :0 核心对象已被激活
WAIT_ABANDONED :128 当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值
WAIT_ABANDONED_0:WAIT_ABANDONED
WAIT_TIMEOUT :258 等待超时
WAIT_FAILED :-1 出现错误,可通过GetLastError得到错误代码
//当线程正在执行时,线程对象处于未激发状态。当线程结束时,线程对象就被激发了。
//等待多个(核心)对象
DOWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles,
BOOL bWaitAll, DWORD dwMiliseconds);
bWaitAll为ture时,等待数组中所有的对象被激发;false时返回被激发对象在数组中的下标。
//临界区
CRITICAL_SECTION critical_sec;
//定义一个临界区,名字为critical_sec
void InitializeCriticalSection(LPCRITICAL_SECTION IpCriticalSection);//初始化临界区
void DeleteCriticalSection(LPCRITICAL_SECTION IpCriticalSection);
//删除临界区
void EnterCriticalSection(LPCRITICAL_SECTION IpCriticalSection);
//进入临界区
void LeaveCriticalSection(LPCRITICAL_SECTION IpCriticalSection);
//离开临界区
//互斥器
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES IpMutexAttibutes,//安全属性
BOOL bInitialOwner,
//初始化后是否属于初始化线程
LPCWSTR IpName);
//mutex的名字
WaitSingleObject();
//获得互斥器
BOOL ReleaseMutex(HANDLE hMutex);//释放互斥器
如果一个线程结束时没有释放互斥器,下一个等待中的线程的等待会以WAIT_ABANDONED_0返回。
CloseHandle();
//删除互斥器
//信号量
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemAttributes,//安全属性
LONG lInitialCount,
//信号量初始值
LONG lMaximumCount,
//信号量的最大值
LPCWSTR lpName);
//名字
WaitForSingleObject();
//获得一个信号量
BOOL ReleaseSemphore(HANDLE hSem, LONG IReleaseCount,LPLONG IpPreviousCount);
//释放信号量,第二个参数说明释放几个,第三个参数接收存储释放前信号量的值的地址
CloseHandle();//删除信号量
//事件
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEveAttr,//安全属性
BOOL bManualReset,
//是否手动设置为非激活
BOOL bInitialState,
//初始状态,激活或者非激活
LPCWSTR lpName);
//名字
BOOL SetEvent(HANDLE hEvent);//设置事件为激活状态
BOOL PulseEvent(HANDLE hEvent);//设置事件为激活状态
说明:SetEvent()和PulseEvent()没有区别;
当事件设置为“手动非激活”时,这两个函数激活事件唤醒所有的阻塞;
当事件设置为“自动非激活”时,事件的激活唤醒一个阻塞。
//我理解为手动Reset比较慢,其他线程还有机会被唤醒,而自动的是系统干的,很速度地Reset了,所以其他线程也就没有机会了。
WaitForSingleObject();
//等待事件
BOOL ResetEvent(HANDLE hEvent);//设置事件为非激活状态
CloseHandle();
//删除事件
//原子操作函数
LONG InterlockedIncrement(LPLONG IpTarget);//加1,并返回加1后的值
LONG InterlockedDecrement(LPLONG IpTarget);//减1,并返回减1后的值
LONG InterlockedExchange(LPLONG IpTarget, LONG IValue);//设定新的值,返回旧的值
//运行线程,挂起线程
DWORD ResumeThread(HANDLE hThread);
//让挂起的进程继续运行(如创建线程时设置倒数第二个参数使线程创建后立刻挂起,调用该函数再让它运行)
DWORD SuspendThread(HANDLE hThread);//挂起进程