第七章 线程调度、优先级、亲和力
1.挂起和恢复线程 (1)ResumeThread 被挂起的线程不会被调度,只有线程调用ResumeThread()的次数等于SuspendThread()时,线程才会被调度。 线程可以Suspend自已但是不能Resume自已。因为被挂起后不会被调度,从而不会执行线程函数内的代码.
(2)SuspendThread 挂起线程时一定要小心 必须明确知道线程在干什么才能决定是否挂起线程。因为当线程正在堆分配内存时,它会给这个堆加上锁。 此时如果将线程挂起,其它线程若想在堆上分配内存则会进入无限等待 直到堆的锁被挂起的线程解开。从而导致死锁。
2.挂起和恢复进程
Windows中并不存在挂起和恢复进程的概念。因为Windows中是以线程为单位来调度和分配CPU的。进程只相当于是一个承载线程的容器,系统不会给进程分配任何CPU.
我们可以把挂起进程理解为挂起进程中所有的线程。Windows并没有提供此类API,但是我们可以通过CreateToolhelp32Snapshot()来实现我们自制的SuspendProcess(). 因为CreateToolhelp32Snapshot只是创建某个进程在某一时刻的快照(如进程占有的内存,进程中有多少正在运行的线程)。 然后通过Thread32First()和Thread32Next()来遍历快照中所得的所有线程。 这么做容易出一些问题 比如通过Thread32Next()取得线程ID后 线程可能立刻就终止了。同样随时会有新的线程产生,而快照中不会反应有出新产生的线程, 从而也就无法挂起该线程。
3.Sleep和SwitchThread (1)Sleep 线程调用Sleep函数后会进入睡眠状态 系统会不调度该进程。 Sleep(0)的意思是让当前线程让出CPU给同或高优先级线程用,但不会把CPU让给比优先级低级的线程。
(2)SwitchThread 与Sleep(0)相同,SwitchThread会迫使当前线程让出CPU级其它线程用。若无其它线程则该函数立即返回。 不同的是SwitchThread允许低优先级的线程使用CPU.
4.优先级 (1)设置优先级 线程的优先级和进程的优先级是相关的。改变进程的优先级会同时改变线程的优先级。也可把进程的优先称做线程的基优先级。 虽然进程有优先级但进程并不可调度,进程优先级只是种抽象的概念,帮助我们脱离调度器的内部工作原理。
SetPriorityClass和GetPriorityClass用来设置和获得进程的优先级。 SetThreadPriority和GetThreadPriority用来设置和获得线程的优先级。
(2)动态提升优先级 默认情况下Windows会动态提升一些线程或进程的优先级从而避免当高线程优先级垄断CPU. 提高低线程的优先级让它获取CPU.当线程执释放CPU时会立刻降到原来的优先级。 我们可以能过以下方法来设置或获取线程或进程的动态优先级设置。从而允许或禁止系统动态提升优先级。 SetProcessPriorityBoost,SetThreadPriorityBoost GetProcessPriorityBoost,GetThreadPriorityBoost
a thread is not allowed to change the I/O priority of another thread.
Code example:
DWORD dwThreadID;
HANDLE hThread = CreateThread(NULL, 0, ThreadFunc, NULL,CREATE_SUSPENDED, &dwThreadID);
SetThreadPriority(hThread, THREAD_PRIORITY_IDLE);
ResumeThread(hThread);
CloseHandle(hThread);
5.Affinity SetProcessAffinityMask 限制某进程中的线程 只能在指定的几个CPU上运行。也用通过Job内核对象限制Job中的所有进程只能在指定的CPU上运行。 SetThreadAffinityMask 限制线程只能在指定的CPU上运行。其被指定的CPU必须是进程所指定的CPU的子集。 GetSystemInfo() 查看CPU信息
6.Common API:
DWORD ResumeThread(HANDLE hThread); DWORD SuspendThread(HANDLE hThread); CreateToolhelp32Snapshot() Thread32First() Thread32Next() Sleep() GetThreadContext() SetThreadContext() |
|