您的位置:首页 > 其它

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

2009-08-29 17:09 253 查看
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的形式不是关键。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息