关于超时问题与线程调度的问题

来源:互联网 发布:windows tar压缩文件 编辑:程序博客网 时间:2024/06/18 17:50

1. 线程限制
  在应用服务器中打流量,发现存在命令超时问题
  分析:线程已经被唤醒,但是得不到调度。
   操作系统是Linux-2.6.17,内核被设置为非抢占式内核,因此一旦一个内核线程得到调度,且该线程总是获得资源而没有阻塞,那么该线程将一直运行下去,其它线程得不到调度。
  超时问题解决的核心是清除线程长期霸占CPU的情况。由于每个用户连接对应多个内核线程,也需要消除一个阵列霸占CPU的情况,从而避免其他阵列线程得不到调度。

 

2. 时间片
  普通线程的时间片时根据动态优先级计算出来的,其更新时机是在时钟中断中进行,具体函数是schedule_tick(),该函数会递减时间片计数器,检查当前线程时间片是否用完,如果是,则是根据动态优先级重新赋值,并设置TIF_NEED_RESCHED标志。
  在许多执行长迭代任务的程序中需要直接调用调度程序,具体函数是schedule(),每次迭代循环时,程序需要检查TIF_NEED_RESCHED标志,如果需要就调用schedule()自动放弃CPU,示例代码如下:
  while(1)
  {
      do something;
      if(test_thread_flag(TIF_NEED_RESCHED))
         schedule();//或者调用yield()
  }
  在linux-2.6.17内核中,普通线程的基本时间片是100ms,另外内核提供yield()函数允许线程在不被挂起的情况下自愿放弃CPU,线程仍处于TASK_RUNNING状态。
  当然,在抢占式内核中,中断处理程序返回内核空间的时候,如果当前线程的时间片已经耗尽且其正在执行的代码不在锁中,则会发生线程切换。

 

3. 改进的处理方式
  1) 修改线程的优先级别,让所有线程都是普通线程优先级别。
  2) 当一个线程处理一定的命令数后(或者在while(1)中循环一定数后),主动调用yield()函数释放CPU。
  原因:所有线程优先级相同,防止高优先级线程被反复调用,同时线程处理一定命令后,通过yield()函数主动释放CPU,防止同一线程被反复调用。虽然这种调控方法不精确,但是粗略地调和了非抢占式内核的线程调度。

 

4. 当前处理方式
  内核态的几种方式:
  1) kernel_thread 启动一个内核线程,其优先级别为普通优先级别,在进入while循环之前调用daemonize()函数去掉用户空间资源。
  2)kthread_create,kthread_run启用一个工作队列,其优先级别高于普通线程
  3)采用工作队列work_queue方式,这种方式的线程优先级别为SW<,表示该线程优先级别高于普通线程,工作队列属于软中断的一种方式,但可以阻塞。
  4)软中断,中断 中断服务例程是系统中优先级最高的任务,会中断线程的处理。
  用户态创建线程的方式
  1)pthread_create 创建普通优先级别的线程

 

5. 线程释放CPU的方式
  1) 采用定时睡眠方式
  2) 采用信号量或wait_event
  3) 内核调度模式
        __set_current_state(TASK_INTERRUPLIBLE);
        if(资源获取)
            schedule();
        __set_current_state(TASK_RUNNING);
  4) 工作队列 work_queue
         执行完毕后,由OS执行CPU切换。
  5) 信号sigwait select
  这种出现在用户态中线程,sigwait使用的是信号,select类似信号量。

 

6. 总结
  在确定需要创建一个线程后,那么就需要考虑创建线程的方式,调用内核中不同函数就会创建不同优先级别的线程。大多数情况下,不需要创建高级别的线程,应用系统中的线程优先级分配是需要根据应用而确定的。
  在线程的运行过程中,什么时候阻塞也需要加以考虑,防止类似死循环的情况发生。至于如何阻塞线程,也就是释放CPU的形式不是关键。

 

原创粉丝点击