2)线程的调度、优先级

(一)暂停线程的运行
     (1)在线程内核对象的内部有一个值,用于指明线程的暂停计数。
  当调用CreateThread函数时,创建了线程的内核对象,并将它的暂停计数初始化为1,防止线程被调度到CPU中。这是很有用的,因为线程的
  初始化需要时间,你不希望在系统做好充分的准备之前就开始执行线程。
  当线程完全初始化了之后,CreateThread要查看是否已经传递了CREATE_SUSPENDED标志。如果传递了这个标志,那么这些函数就返回,
  同时新线程处于暂停状态。如果尚未传递该标志,那么该函数将线程的暂停计数递减为0。当线程的暂停计数是0的时候,除非线程正在等待
  其他某种事情的发生,否则该线程就处于可调度状态。
  (2)当创建线程时,除了使用CREATE_SUSPENDED外,也可以调用SuspendThread函数来暂停线程的运行。
    DWORD SuspendThread(HANDLE hThread);
    函数返回的是线程的前一个暂停计数。
    注意:调用该函数要小心,因为不知道暂停线程运行时它在进行什么操作。如果线程试图从堆栈中分配内存,那么该线程将在该堆栈上设置一个锁。
       当其他线程试图访问该堆栈时,这些线程的访问就被停止,直到第一个线程恢复运行。只有确切直到目标线程是什么,并且
    采取强有力的措施来避免因暂停线程的运行而带来的问题或死锁状态,SuspendThread才是安全的。


(二)恢复线程的运行
     DWORD ResumeThread(HANDLE hThread);
  如果函数运行成功,它将返回线程的前一个暂停计数,否则返回0xFFFFFFFF.
  单个线程可以暂停若干次。如果一个线程暂停了3次,它必须恢复3次,然后它才可以被分配给一个CPU。


(三)睡眠方式
     线程也能告诉系统,它不想在某个时间段内被调度。可以通过调用Sleep函数来实现:
  void Sleep(DWORD dwMilliseconds);
  该函数可使线程暂停自己的运行,知道dwMilliseconds过去为止。
  关于Sleep函数,有下面几个重要问题值得注意:
 (1)调用Sleep,可使线程自愿放弃它剩余的时间片;
 (2)系统将在大约的指定毫秒属内使线程不可调度。Windows不是个实时操作的系统。虽然线程可能在规定的时间被唤醒,但它能否做到,
      取决于系统中还有什么操作正在进行。
 (3)当传递INFINITE时,这将告诉系统永远不要调度该线程。这不是一件值得去做的事情,最好让线程退出,并还原它的堆栈和内核对象
 (4)当传递0时,调用线程将释放剩余的时间片,并迫使系统调用另一个线程。但是,系统可以对刚刚调用Sleep的相乘重新调度。


(四)转换到另一个线程
    BOOL SwitchToThread();
 当调用这个函数时,系统要查看是否存在一个迫切需要CPU时间的线程。如果没有线程迫切需要CPU时间,函数返回FALSE。如果存在一个
 迫切需要CPU时间的线程,SwitchToThread就对该线程进行调度,函数返回一个非0值。
 该函数允许一个需要资源的线程强制另一个优先级较低、而目前却拥有该资源的线程放弃该资源。


(五)线程的运行时间
     有时想要计算线程执行某个任务需要多长时间。许多人采取的办法如下:
  DWORD dwStartTime=GetTickCount();
  DWORD dwElapsedTime=GetTickCount()-dwStartTime;
  这个代码做了一个简单的假设:即他不会被中断。但是,在抢占式操作系统中,永远无法知道线程合适被赋予CPU时间。
  当取消线程的CPU时间时,就更难计算线程执行不同任务时所用的时间。
  我们需要一个函数,以便返回线程得到的CPU时间的数量。
  BOOL GetThreadTimes(
  HANDLE hThread;
  PFILETIME pftCreationTime,  //相乘创建的时间
  PFILETIME pftExitTime;   //线程退出时间,如果线程仍然运行,退出时间未定义
  PFILETIME pftKernerTime, //一个相对值,指明线程执行操作系统代码已经经过了多少个100ns的CPU时间
  PFILETIME pftUserTime   //一个相对值,指明线程执行应用程序代码已经经过了多少个100ns的CPU时间
  );


(六)线程的优先级
    抢占式操作系统必须使用某种算法来确定哪些线程应该在何时调度和运行多长时间。
 每隔20ms左右,Windows要查看当前存在的所有线程内核对象。在这些对象中,只有某些对象被视为可以调度的对象。
 Windows选择可调度的线程内核对象中的一个,将它加载到CPU寄存器中,它的值是上次保存在线程的环境中的值,这项操作称为上下文转换。
 每个线程都会被赋予一个从0(最低)到31(最高)的优先级号码。
 相对的线程优先级:
 *关键时间(RHREAD_PRIORITY_TIME_CRITICAL):对于实时优先级类来说,线程在优先级31运行,对于其他优先级类来说,线程在优先级15上运行
 *最高(RHREAD_PRIORITY_HIGHEST):线程在高于正常优先级的上两级上运行
 *高于正常(RHREAD_PRIORITY_ABOVE_MORMAL):线程在正常优先级的上一级上运行
 *正常(RHREAD_PRIORITY_NORMAL):线程在进程的优先级类上正常运行
 *低于正常(RHREAD_PRIORITY_BELOW_NORMAL):线程在低于正常优先级的下一级上运行
 *最低(RHREAD_PRIORITY_LOWEST):线程在低于正常优先级的下两极上运行
 *空闲(RHREAD_PRIORITY_IDLE):对于实时优先级类来说,线程在优先级16上运行,对于其他优先级类来说,线程在优先级1上运行。
 
  当一个线程刚刚创建时,它的相对线程优先级总是设置为正常优先级。
  设置线程优先级:
  BOOL SetThreadPriority(HANDLE hThread,int nPriority);
 
  获得线程优先级:
  int GetThreadPriority(HANDLE hThread);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

猜你喜欢

转载自blog.csdn.net/u010901792/article/details/72991962