本文共 2120 字,大约阅读时间需要 7 分钟。
贴几篇文章先...
记录些概念和接口。
1. 什么是睡眠?
cpu调度 有 按时间片轮转, 抢占式基于优先级, 实时调度等很多方式。
不同场景使用不同调度方式。
比如Linux就是一个非硬实时的, 抢占式基于优先级, 也按时间片轮转的调度系统。
VxWorks, Nuclues等为实时操作系统(RTOS)。
简单说, 线程被挂起, cpu去干别的事了, 该线程就算睡眠了...
2. 如何睡眠?
1). 被动睡眠, 比如时间片到了, cpu调度其他线程。irq中断来了, cpu去执行isr中断处理函数等。
2). 主动睡眠, 设置当前状态为TASK_INTERRUPTIBLE, 然后调用schedule()或者schedule_timeout()函数。
会主动放弃cpu, 进入挂起状态。
3. 等待队列的使用场景?
1). 以IO操作为例, 用户态读写操作时, 如果内核态文件系统/驱动设备 不满足情况。通常会阻塞住这次IO调用。
即read, write需要等待设备/数据ready后, 才能读出, 写入数据。
内核态有几种实现方式,
A. 循环判断设备状态/数据是否ready, ok后完成这次IO。 - 这样子就是白白浪费cpu了。
B. 直接返回-EAGAIN等错误, 让用户下次再来读写...
这就是非阻塞式IO(但不是异步IO), 比如有些alsa 接口, snd_pcm_read, snd_pcm_write等等。都是非阻塞IO的情况。
(这种有很多, 只要能返回-EAGAIN那种, 都是非阻塞IO)
C. 依然阻塞方式, 内核态可以使用等待队列的方式, 主动放弃cpu执行, 如此就能减低cpu负载了。
D. 顺便提一句异步IO, 即AIO, 所谓异步, 通常以注册回调函数的方式来实现。 即注册读写IO 到内核态, 当内核态有IO数据后,
调用用户态的IO回调函数, 这就算异步IO。我也用的不多... 先暂时不管了...
E. 哦, 还有种poll, select, epoll这种, 是多路复用IO的接口, 通常一个设备IO即一个fd文件描述符的读写, 我们直接使用read, write函数阻塞等待就是了。 但如果用户态进程, 需要同时监听多个设备的IO, 一般来说就几种方式...
(1) 起多进程, 或者多线程, 每个线程独立读写对应设备。 - 浪费...
(2) 单个进程, 循环挨个读写设备.... - 浪费...
(3) 多路复用IO, poll, select, epoll 一个文件描述符的数组, 当数组内的设备IO 准备就绪后, 在针对性地执行读写操作。 - 好办 法!
3. 如何使用等待队列?
差点又忘了正题, 关于如何使用等待队列。 内核中已经封装好一些接口。
1). 创建等待队列头部,
DECLARE_WAIT_QUEUE_HEAD(name)
或者
wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);
2). 简单睡眠...
内核中定义了很多帮助宏, 创建完等待队列后, 简单使用以下宏就可以使当前线程挂起并进入等待队列。
wait_event(queue, condition)
wait_event_interruptible(queue, condition)
wait_event_timeout(queue, condition, timeout)
wait_event_interruptible_timeout(queue, condition, timeout)
*简单睡眠如何唤醒。两个宏
void wake_up(wait_queue_head_t *queue)
void wake_up_interruptible(wait_queue_head_t *queue)
3). 手动睡眠
稍微复杂点, 不用上面那些宏。
在第一步已经创建了等待队列头部,
A. 下面创建一个等待队列条目。
DECLARE_WAITQUEUE(name, task)
B. 将等待队列条目 放入等待队列中
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
C. 设置线程状态
set_current_state(TASK_INTERRUPTIBLE)
D. 进程调度
schedule() 或者 schedule_timeout()
关于内核中如何实现...后面看懂了继续。
总结一下:
如何使用等待队列, 简单明了:
1. 创建等待队列头部, 创建等待队列项目。
2. 将等待队列条目加入等待队列中。
3. 设置当前进程/线程状态。
4. 进程/线程调度。
转载地址:http://xpcrj.baihongyu.com/