小CASE,为什么CPU空闲时间被一个服务线程占领!

mao1975 2002-01-02 03:19:31
用BCB5的Service Application Warzid创建一个服务应用程序,运行后发现有两个问题;1。系统CPU的CPU空闲时间被一个服务线程占领,2。系统在注销/重起时该服务进程无法自动终止。
HAPPY NEW YEAR!
...全文
127 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
xiaoxiaohan 2002-01-06
  • 打赏
  • 举报
回复
0 优先级保留供零页线程使用,
系统不允许任何其他线程拥有0 优先级。另外,下列优先级等级是无法使用的:1 7 、1 8 、1 9 、
2 0 、2 1 、2 7 、2 8 、2 9 和3 0 。如果编写一个以内核方式运行的设备驱动程序,可以获得这些优先
级等级,而用户方式的应用程序则不能。另外还要注意,实时优先级类中的线程不能低于优先
级等级1 6 。同样,非实时优先级类中的线程的等级不能高于1 5 。
注意有些人常常搞不清进程优先级类的概念。他们认为这可能意味着进程是可以调
度的。但是进程是根本不能调度的,只有线程才能被调度。进程优先级类是个抽象概
念,M i c r o s o f t 提出这个概念的目的,是为了帮助你将它与调度程序的内部运行情况区
分开来。它没有其他目的。
注意一般来说,大多数时候高优先级的线程不应该处于可调度状态。当线程要进行
某种操作时,它能迅速获得C P U 时间。这时线程应该尽可能少地执行C P U 指令,并返
回睡眠状态,等待再次变成可调度状态。相反,低优先级的线程可以保持可调度状态,
执行大量的C P U 指令来进行它的操作。如果按照这些原则来办,整个操作系统就能正
确地对用户作出响应。
xiaoxiaohan 2002-01-06
  • 打赏
  • 举报
回复
每个线程都会被赋予一个从0 (最低)到3 1 (最高)的优先级号码。当系统确定将哪个线
程分配给C P U 时,它首先观察优先级为3 1 的线程,并以循环方式对它们进行调度。如果优先级
为3 1 的线程可以调度,那么就将该线程赋予一个C P U 。在该线程的时间片结束时,系统要查看
是否还有另一个优先级为3 1 的线程可以运行,如果有,它将允许该线程被赋予一个C P U 。
只要优先级为3 1 的线程是可调度的,系统就绝对不会将优先级为0 到3 0 的线程分配给C P U 。
这种情况称为渴求调度(s t a r v a t i o n )。当高优先级线程使用大量的C P U 时间,从而使得低优先
级线程无法运行时,便会出现渴求情况。在多处理器计算机上出现渴求情况的可能性要少得多,
因为在这样的计算机上,优先级为3 1 和优先级为3 0 的线程能够同时运行。系统总是设法使C P U
保持繁忙状态,只有当没有线程可以调度的时候,C P U 才处于空闲状态。
人们可能认为,在这样的系统中,低优先级线程永远得不到机会运行。不过正像前面指出
的那样,在任何一个时段内,系统中的大多数线程是不能调度的。例如,如果进程的主线程调
用G e t M e s s a g e 函数,而系统发现没有线程可以供它使用,那么系统就暂停进程的线程运行,释
放该线程的剩余时间片,并且立即将C P U 分配给另一个等待运行的线程。
如果没有为G e t M e s s a g e 函数显示可供检索的消息,那么进程的线程将保持暂停状态,并且
决不会被分配给C P U 。但是,当消息被置于线程的队列中时,系统就知道该线程不应该再处于
暂停状态。此时,如果没有更高优先级的线程需要运行,系统就将该线程分配给一个C P U 。
现在考虑另一个问题。高优先级线程将抢在低优先级线程之前运行,不管低优先级线程正
在运行什么。例如,如果一个优先级为5 的线程正在运行,系统发现一个高优先级的线程准备
要运行,那么系统就会立即暂停低优先级线程的运行(即使它处于它的时间片中),并且将
C P U 分配给高优先级线程,使它获得一个完整的时间片。
还有,当系统引导时,它会创建一个特殊的线程,称为0 页线程。该线程被赋予优先级0 ,
它是整个系统中唯一的一个在优先级0 上运行的线程。当系统中没有任何线程需要执行操作时,
0 页线程负责将系统中的所有空闲R A M 页面置0 。
xiaoxiaohan 2002-01-06
  • 打赏
  • 举报
回复
1. 如何暂停和恢复线程的运行?
线程内核对象的内部有一个值指明线程的暂停计数。当调用CreateProcess或CreateThread函数时,就创建了线程的内核对象,并且它的暂停计数被初始化为1。因为线程的初始化需要时间,不能在系统做好充分的准备之前就开始执行线程。线程完全初始化好了之后,CreateProcess或CreateThread要查看是否已经传递了CREATE_SUSPENDED标志。如果已经传递了这个标志,那么这些函数就返回,同时新线程处于暂停状态。如果尚未传递该标志,那么该函数将线程的暂停计数递减为0。当线程的暂停计数是0的时候,除非线程正在等待其他某种事情的发生,否则该线程就处于可调度状态。在暂停状态中创建一个线程,就能够在线程有机会执行任何代码之前改变线程的运行环境(如优先级)。一旦改变了线程的环境,必须使线程成为可调度线程。方法如下:
hThread = CreatThread( ……,CREATE_SUSPENDED,…… );

bCreate = CreatProcess( ……,CREATE_SUSPENDED,……,pProcInfo );
if( bCreate != FALSE )
{
hThread = pProcInfo.hThread;
}
……
……
……
ResumeThread( hThread );
CloseHandle( hThread );
ResumeThread成功,它将返回线程的前一个暂停计数,否则返回0xFFFFFFFF。
单个线程可以暂停若干次。如果一个线程暂停了3次,它必须恢复3次。创建线程时,除了使用CREATE_SUSPENDED外,也可以调用SuspendThread函数来暂停线程的运行。任何线程都可以调用该函数来暂停另一个线程的运行(只要拥有线程的句柄)。线程可以自行暂停运行,但是不能自行恢复运行。与ResumeThread一样,SuspendThread返回的是线程的前一个暂停计数。线程暂停的最多次数可以是MAXIMUM_SUSPEND_COUNT次。SuspendThread与内核方式的执行是异步进行的,但是在线程恢复运行之前,不会发生用户方式的执行。调用SuspendThread时必须小心,因为不知道暂停线程运行时它在进行什么操作。只有确切知道目标线程是什么(或者目标线程正在做什么),并且采取强有力的措施来避免因暂停线程的运行而带来的问题或死锁状态,SuspendThread才是安全的。
2. 是否可以暂停和恢复进程的运行?
对于Windows来说,不存在暂停或恢复进程的概念,因为进程从来不会被安排获得CPU时间。不过Windows确实允许一个进程暂停另一个进程中的所有线程的运行,但是从事暂停操作的进程必须是个调试程序。特别是,进程必须调用WaitForDebugEvent和ContinueDebugEvent之类的函数。由于竞争的原因,Windows没有提供其他方法来暂停进程中所有线程的运行。
3. 如何使用sleep函数?
•系统将在大约的指定毫秒数内使线程不可调度。Windows不是个实时操作系统。虽然线程可能在规定的时间被唤醒,但是它能否做到,取决于系统中还有什么操作正在进行。
•可以调用Sleep,并且为dwMilliseconds参数传递INFINITE。这将告诉系统永远不要调度该线程。这不是一件值得去做的事情。最好是让线程退出,并还原它的堆栈和内核对象。
•可以将0传递给Sleep。这将告诉系统,调用线程将释放剩余的时间片,并迫使系统调度另一个线程。但是,系统可以对刚刚调用Sleep的线程重新调度。如果不存在多个拥有相同优先级的可调度线程,就会出现这种情况。
4. 如何转换到另一个线程?
系统提供了SwitchToThread函数。当调用这个函数的时候,系统要查看是否存在一个迫切需要CPU时间的线程。如果没有线程迫切需要CPU时间,SwitchToThread就会立即返回。如果存在一个迫切需要CPU时间的线程,SwitchToThread就对该线程进行调度(该线程的优先级可能低于调用SwitchToThread的线程)。这个迫切需要CPU时间的线程可以运行一个时间段,然后系统调度程序照常运行。该函数允许一个需要资源的线程强制另一个优先级较低、而目前却拥有该资源的线程放弃该资源。如果调用SwitchToThread函数时没有其他线程能够运行,那么该函数返回FALSE,否则返回一个非0值。调用SwitchToThread与调用Sleep是相似的。差别是SwitchToThread允许优先级较低的线程运行;而即使有低优先级线程迫切需要CPU时间,Sleep也能够立即对调用线程重新进行调度。
5. 如何取得线程运行的时间?
(1) 简单取得线程大概运行时间:
DWORD dwStartTime = 0;
DWORD dwEndTime = 0;
DWORD dwRunTime = 0;
dwStartTime = GetTickCount( );
……
……
……
dwEndTime = GetTickCount( );
dwRunTime = dwEndTime – dwStartTime;
(2) 调用GetThreadTimes的函数:
参数 含义
hThread 线程句柄
lpCreationTime 创建时间:英国格林威治时间
lpExitTime 退出时间:英国格林威治时间,如果线程仍然在运行,退出时间则未定义
lpKernelTime 内核时间:指明线程执行操作系统代码已经经过了多少个100ns的CPU时间
lpUserTime 用户时间:指明线程执行应用程序代码已经经过了多少个100ns的CPU时间
GetProcessTimes是个类似GetThreadTimes的函数,适用于进程中的所有线程(甚至是已经终止运行的线程)。返回的内核时间是所有进程的线程在内核代码中经过的全部时间的总和。GetThreadTimes和GetProcessTimes这两个函数在Windows98中不起作用。在Windows98中,没有一个可靠的机制可供应用程序来确定线程或进程已经使用了多少CPU时间。
6. 进程的优先级类有哪些?
优先级类 标识符 描述
实时 REALTIME_PRIORITY_CLASS 立即对事件作出响应,执行关键时间的任务。会抢先于操作系统组件之前运行。
高 HIGH_PRIORITY_CLASS 立即对事件作出响应,执行关键时间的任务。
高于正常 ABOVE_NORMAL_PRIORITY_CLASS 在正常优先级与高优先级之间运行(Windows2000)。
正常 NORMAL_PRIORITY_CLASS 没有特殊调度需求
低于正常 BELOW_NORMAL_PRIORITY_CLASS 在正常优先级与空闲优先级之间运行(Windows2000)。
空闲 IDLE_PRIORITY_CLASS 在系统空闲时运行。
设置方法:
BOOL SetPriorityClass( HANDLE hProcess, DWORD dwPriority );
DWORD GetPriorityClass( HANDLE hProcess );
使用命令外壳启动一个程序时,该程序的起始优先级是正常优先级。如果使用Start命令来启动该程序,可以使用一个开关来设定应用程序的起始优先级。例如:
c:\>START /LOW CALC.EXE
Start命令还能识别/BELOWNORMAL、/NORMAL、/ABOVENORMAL、/HIGH和/REALTIME等开关。
7. 线程的相对优先级有哪些?
相对优先级 标识符 描述
关键时间 THREAD_PRIORITY_TIME_CRITICAL 对于实时优先级类线程在优先级31上运行,对于其他优先级类,线程在优先级15上运行。
最高 THREAD_PRIORITY_HIGHEST 线程在高于正常优先级上两级上运行。
高于正常 THREAD_PRIORITY_ABOVE_NORMAL 线程在正常优先级上一级上运行。
正常 THREAD_PRIORITY_NORMAL 线程在进程的优先级类上正常运行。
低于正常 THREAD_PRIORITY_BELOW_NORMAL 线程在低于正常优先级下一级上运行。
最低 THREAD_PRIORITY_LOWEST 线程在低于正常优先级下两级上运行。
空闲 THREAD_PRIORITY_IDLE 对于实时优先级类线程在优先级16上运行对于其他优先级类线程在优先级1上运行。
设置方法:
BOOL SetThreadPriority( HANDLE hThread, DWORD dwPriority );
DWORD GetThreadPriorityClass( HANDLE hThread );
8. 如何避免系统动态提高线程的优先级等级?
系统常常要提高线程的优先级等级,以便对窗口消息或读取磁盘等I/O事件作出响应。或者当系统发现一个线程在大约3至4s内一直渴望得到CPU时间,它就将这个渴望得到CPU时间的线程的优先级动态提高到15,并让该线程运行两倍于它的时间量。当到了两倍时间量的时候,该线程的优先级立即返回到它的基本优先级。下面的函数可以对系统的调度方式进行设置:
BOOL SetProcessPriorityBoost( HANDLE hProcess, BOOL bDisableBoost );
BOOL GetProcessPriorityBoost( HANDLE hProcess, PBOOL pbDisableBoost );
BOOL SetThreadPriorityBoost( HANDLE hThread, BOOL bDisableBoost );
BOOL GetThreadPriorityBoost( HANDLE hThread, PBOOL pbDisableBoost );
SetProcessPriorityBoost负责告诉系统激活或停用进行中的所有线程的优先级提高功能,而SetThreadPriorityBoost则激活或停用各个线程的优先级提高功能。Windows98没有提供这4个函数的有用的实现代码。
VSaber 2002-01-03
  • 打赏
  • 举报
回复
就是system的idle嘛!
大大怪老张 2002-01-03
  • 打赏
  • 举报
回复
关注

552

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 茶馆
社区管理员
  • 茶馆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧