这是收集于网络的一些线程编程资料.
进程由两部分组成:进程内核对象, 地址空间。进程是不活泼的,它的执行依赖于线程。
线程由两部分组成:线程内核对象,线程堆栈。
创建新线程:
DWORD WINAPI FUNC(PVOID pvParam)
int Param;
DWORD dwThreadID;
CreateThread(NULL,0,FUNC,(PVOID)&Param,0,&dwThreadID);
检查线程是否退出:
BOOL GetExitCodeThread(HANDLE hThread,PDWORD pdwExitCode);//如果还未终止,得到0x103.
获得伪句柄:
GetCurrentProcess()
GetCurrentThread()
获得运行时间:
GetProcessTimes()
GetThreadTimes()
线程或进程的伪句柄转化为实句柄:
DuplicatgeHandle();//此函数会增加内核对象的引用计数。
伪句柄用于本线程,获得这个句并不会影响内核对象的计数,而实句柄用于传递给子进程。
线程的暂停和运行:
ResumeThread(HANDLE)
SuspendThread(HANDLE) //使用此函数要小心死锁。
线程休眠:
Sleep(DWORD dwMilliseconds);
自动退出当前时间片:
SwitchtoThread();
可以获得和修改线程的上下文,使用之前要SuspendThread()
GetThreadContext()
SetThreadContext()
改变进程的优先级://记住进程是不可以调度的,调度的单位是线程。
BOOL SetPriorityClass();
DWORD GetPriorityClass();
设定线程的相对优先级:
int GetThreadPriority(HANDLE hThread);
BOOL SetThreadPriority(Handle hThread,int nPriority);
Microsoft保留了随时修改调度算法的权利,因此使用相对优先级,可以保证程序在将来的系统上也可以正常运行。
结合进程优先级和线程的相对优先级,就可以得到线程的基本优先级。线程的当前优先级不可以低于基本优先级,
也就是说,系统会提高线程的优先级,并随着执行时间片的流逝降低优先级,但降到基本优先级后就不再降了。
优先级0-15成为动态优先级范围,高于15是实时范围,系统不会调度实时范围线程的优先级,也不会把动态优先级范围的线程提高到15以上。
亲缘性是对多处理器系统来说的,为了能利用保留在cpu高速缓存和NUMA(非统一内存访问)结构计算机本插件板上内存中的数据,系统尽量线程上次运行使用的CPU来运行线程,包括软亲缘性(WIN2000默认)和硬亲缘性(用户可以选择CPU)
相关的函数有:
BOOL SetProcessAffinityMask(HANDLE hProcess,DWORD_PTR dwProcessAffinityMask);
BOOL GetProcessAffinityMask(Handle hProcess,PDWORD_PTR pdwProcessAffinityMask,PDWORD_PTR pdwSystemAffinityMask);
DWORD_PTR SetThreadAffinityMask(HANDLE hThread,DWORD_PTR dwThreadAffinityMask);
DWORD_PTR SetThreadIdealProcessor(HANDLE hThread,DWORD dwIdealProcessor);
临界区保证其中的资源(通常是各种共享变量)被原子的访问,当进入临界区后,其他访问这些资源的线程将不会被调度。
线程同步包括用户方式和内核方式,用户方式包括原子操作和临界区,它的特点是速度快,但功能有限。内核方式利用内核对象的通知状态来同步线程,由于需要由用户方式切换到内核方式(这种切换很废时间),且系统要进行很多操作,效率较低,但功能强大(能够设定超时值等,可以同步多个进程的线程)。
内核方式同步的原理:线程使自己进入休眠状态,等待内核对象由未通知状态变为已通知状态。
可处于未通知状态变和已通知状态的内核对象:进程,线程,作业,文件修改通知,时间,可等待定时器,文件,控制台输入,信号量,互斥体。
进程和线程在建立时处于未通知状态,在退出时变为已通知状态。
等待函数:
DWORD WaitForSingleObject(HANDLE hObject,DWORD dwMilliseconds);
DWORD WaitForMultipleObject(DWORD dwCount,CONST HANDLE* phObjects,BOOL fWaitALL,DWORD dwMilliseconds);其中,
0返回值的含义:
HANDLE h[3];
h[0]=hProcess1;
h[1]=hProcess2;
h[2]=hProcess3;
DWORD dw=WaitForMultipleObject(3,h,FALSE,5000);
switch(dw)
{
case WAIT_FAILED://Bad call to function(invalid handle?)
break;
case WAIT_TIMEOUT://None of the object became signaled within 5000 milliseconds.
break;
case WAIT_OBJECT_0+0:The process identified by h[0] terminated.
break;
case WAIT_OBJECT_0+1:
break;
case WAIT_OBJECT_0+2:
break;
}
//WaitForSingleObject()的返回值只有前三种情况。如果给WaitForMutipleObject()的fWaitAll参数传递TRUE,那么其返回值也只有前三种。
事件内核对象:有两种,人工事件对象:当它得到通知的时候,所有等待的线程都变为可调度线程;自动重置的事件:当事件得到通知的时候,只有一个等待线程变为可调度的线程。创建事件内核对象:
HANDLE CreateEvent(PSECURITY_ATTRIBUTES psa,BOOL fManualReset,BOOL fInitialState,PCTSTR pszName);
将事件改为通知状态:
BOOL SetEvent(HANDLE hEvent);
将事件改为未通知状态:
BOOL ResetEvent(HANDLE hEvent);
如果事件是自动重置事件,那么成功等待会产生副作用,即将事件自动置为未通知状态。如果是人工事件对象,则没有副作用。
等待定时器内核对象:是在某个时间或按规定的间隔时间发出自己的信号通知的内核对象。
HANDLE CreateWaitableTimer(PSECURITY_ATTRIBUTES psa,BOOL fManualReset,PCSTR pszName);
初始总是未通知状态。
BOOL SetWaitableTimer(
HANDLE hTimer,
const LARGE_INTEGER *pDueTime,
LONG lPeriod,
PTIMERAPCROUTINE pfnCompletionRoutine,
PVOID pvArgToCompletionRoutine,
BOOL fResume);
取消定时器:
BOOL CancelWaitableTimer(HANDLE hTimer);
如果仅想改变报时条件,不用调用这个函数暂停报时器,直接调用SetWaitableTimer()就可以了。