记录些等待队列(wait_queue)的使用

贴几篇文章先...

https://blog.csdn.net/hs794502825/article/details/8959459

https://blog.csdn.net/lizuobin2/article/details/51785812


记录些概念和接口。

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. 进程/线程调度。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值