等待队列 阻塞非阻塞
阻塞
设备驱动不阻塞,用户想获取设备资源只能不停的查询,这无谓的消耗CPU资源。而阻塞访问,不能获取资源的进程将进入休眠,它将CPU资源“礼让”给其他进程
唤醒进程的地方最大可能发生在中断里面,因为硬件资源获得的同时往往伴随着一个中断
定义头
wait_queue_head_t queue;
初始化头
#define init_waitqueue_head(q)
定义
#define DECLARE_WAITQUEUE(name, tsk)
添加
extern void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
移除
extern void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
等待事件
#define wait_event(wq, condition)
#define wait_event_timeout(wq, condition, timeout)
#define wait_event_interruptible(wq, condition)
#define wait_event_interruptible_timeout(wq, condition, timeout)
wq:等待队列
condition:必须满足,否则继续阻塞
interruptible:可以被信号打断
timeout:超时时间。不论condition是否满足,均返回
wait_event
#define wait_event(wq, condition) \
do { \
if (condition) //条件满足立即返回 \
break; \
__wait_event(wq, condition); //添加等待队列,阻塞 \
} while (0)
#define __wait_event(wq, condition) \
do { \
DEFINE_WAIT(__wait); \
\
for (;;) { \
prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); \
if (condition) \
break; \
schedule(); //放弃CPU \
} \
finish_wait(&wq, &__wait); \
} while (0)
唤醒
#define wake_up(x)
#define wake_up_interruptible(x)
wake_up和wait_event或wait_event_timeout成对使用,wake_up_interruptible和wait_event_interruptible或wait_event_interruptible_timeout成对使用
wake_up可唤醒处于TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE的进程,wake_up_interruptible只能唤醒处于TASK_INTERRUPTIBLE的进程
在等待队列上睡眠
extern void sleep_on(wait_queue_head_t *q);
extern long sleep_on_timeout(wait_queue_head_t *q,
signed long timeout);
extern void interruptible_sleep_on(wait_queue_head_t *q);
extern long interruptible_sleep_on_timeout(wait_queue_head_t *q,
signed long timeout);
一般不用,而是直接进行状态切换
举例
if (mutex_lock_interruptible(&ir->buf_lock))
return -ERESTARTSYS;
DECLARE_WAITQUEUE(wait, current); //定义等待队列
add_wait_queue(&ir->buf.wait_poll, &wait); //添加等待队列
set_current_state(TASK_INTERRUPTIBLE); //改变进程状态
while (written < n)
{
if (lirc_buffer_empty(&ir->buf))
{
if (filep->f_flags & O_NONBLOCK) //非阻塞
{
ret = -EWOULDBLOCK;
break;
}
if (signal_pending(current)) //因信号唤醒
{
ret = -ERESTARTSYS;
break;
}
schedule(); //调度其他进程
set_current_state(TASK_INTERRUPTIBLE);
}
else
{
lirc_buffer_read(&ir->buf, buf);
ret = copy_to_user((void *)outbuf+written, buf,
ir->buf.chunk_size);
written += ir->buf.chunk_size;
}
}
remove_wait_queue(&ir->buf.wait_poll, &wait); //将等待队列移出等待队列头
set_current_state(TASK_RUNNING); //改变进程状态TASK_RUNNING
mutex_unlock(&ir->buf_lock);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!