Linux内核的等待队列是以双循环链表为基础数据结构,与进程调度机制紧密结合,能够用于实现核心的异步事件通知机制。

在这个链表中,有两种数据结构:等待队列头(wait_queue_head_t)和等待队列项(wait_queue_t)。等待队列头和等待队列项中都包含一个list_head类型的域作为"连接件"。它通过一个双链表和把等待tast的头,和等待的进程列表链接起来。从上图可以清晰看到。所以我们知道,如果要实现一个等待队列,首先要有两个部分。队列头和队列项。下面看他们的数据结构。

struct list_head {struct list_head *next, *prev;
};
struct __wait_queue_head {spinlock_t lock;struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
struct __wait_queue {unsigned int flags;
#define WQ_FLAG_EXCLUSIVE    0x01void *private;//2.6版本是采用void指针,而以前的版本是struct task_struct * task;//实际在用的时候,仍然把private赋值为taskwait_queue_func_t func;struct list_head task_list;
};


所以队列头和队列项是通过list_head联系到一起的,list_head是一个双向链表,在linux内核中有着广泛的应用。并且在list.h中对它有着很多的操作。

 

2.对列头和队列项的初始化:
 wait_queue_head_t my_queue;

init_waitqueue_head(&my_queue);

直接定义并初始化。init_waitqueue_head()函数会将自旋锁初始化为未锁,等待队列初始化为空的双向循环链表。

DECLARE_WAIT_QUEUE_HEAD(my_queue);

定义并初始化

3.定义等待队列: DECLARE_WAITQUEUE(name,tsk);

#define   DECLARE_WAITQUEUE(name,   tsk)       /
wait_queue_t   name     =__WAITQUEUE_INITIALIZER(name,   tsk) #define   __WAITQUEUE_INITIALIZER(name,   tsk)   {         task:     tsk,        task_list:  {  NULL,   NULL   },  __WAITQUEUE_DEBUG_INI(name)}


它的解释是: 
通过DECLARE_WAITQUEUE宏将等待队列项初始化成对应的任务结构,并且用于连接的相关指针均设置为空。其中加入了调试相关代码。 
进程通过执行下面步骤将自己加入到一个等待队列中:
1) 调用DECLARE_WAITQUEUE()创建一个等待队列的项;
2) 调用add_wait_queue()把自己加入到等待队列中。该队列会在进程等待的条件满足时唤醒它。在其他地方写相关代码,在事件发生时,对等的队列执行wake_up()操作。
3) 将进程状态变更为: TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE。
4) 如果状态被置为TASK_INTERRUPTIBLE ,则信号唤醒进程。即为伪唤醒(唤醒不是因为事件的发生),因此检查并处理信号。
5) 检查condition是否为真,为真则没必要休眠,如果不为真,则调用scheduled()。
6) 当进程被唤醒的时候,它会再次检查条件是否为真。真就退出循环,否则再次调用scheduled()并一直重复这步操作。
7) condition满足后,进程将自己设置为TASK_RUNNING 并通过remove_wait_queue()退出。

 

4.(从等待队列头中)添加/移出等待队列

(1)add_wait_queue()函数: (2)remove_wait_queue()函数:

 

5.等待事件:(有条件睡眠)

1)wait_event()宏:

#define wait_event(wq, condition) / do { /
if (condition) /
break; /
__wait_event(wq, condition); /
} while (0) #define __wait_event_timeout(wq, condition, ret) / do { /
DEFINE_WAIT(__wait); /
/
for (;;) { /
prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); /
if (condition) /
break; /
ret = schedule_timeout(ret); /
if (!ret) /
break; /
} /
finish_wait(&wq, &__wait); /
} while (0)


在等待会列中睡眠直到condition为真。在等待的期间,进程会被置为TASK_UNINTERRUPTIBLE进入睡眠,直到condition变量变为真。每次进程被唤醒的时候都会检查condition的值.

(2)wait_event_interruptible()函数:

和wait_event()的区别是调用该宏在等待的过程中当前进程会被设置为TASK_INTERRUPTIBLE状态.在每次被唤醒的时候,首先检查condition是否为真,如果为真则返回,否则检查如果进程是被信号唤醒,会返回-ERESTARTSYS错误码.如果是condition为真,则返回0.

(3)wait_event_timeout()宏:

也与wait_event()类似.不过如果所给的睡眠时间为负数则立即返回.如果在睡眠期间被唤醒,且condition为真则返回剩余的睡眠时间,否则继续睡眠直到到达或超过给定的睡眠时间,然后返回0.

(4)wait_event_interruptible_timeout()宏:

与wait_event_timeout()类似,不过如果在睡眠期间被信号打断则返回ERESTARTSYS错误码.

(5) wait_event_interruptible_exclusive()宏

同样和wait_event_interruptible()一样,不过该睡眠的进程是一个互斥进程.

 

6.唤醒队列:

(1)wake_up()函数:

唤醒等待队列.可唤醒处于TASK_INTERRUPTIBLE和TASK_UNINTERUPTIBLE状态的进程,和wait_event/wait_event_timeout成对使用.

2)wake_up_interruptible()函数: #define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)

和wake_up()唯一的区别是它只能唤醒TASK_INTERRUPTIBLE状态的进程.,与wait_event_interruptible/wait_event_interruptible_timeout/ wait_event_interruptible_exclusive成对使用.

 

TASK_INTERRUPTIBLE,允许通过发送signal唤醒它(即可中断的睡眠状态);

TASK_UNINTERRUPTIBLE,不接收任何 singal

 

7.在等待队列上睡眠:(无条件睡眠,老内核使用,新内核建议不用)

 (1)sleep_on()函数:

该函数的作用是定义一个等待队列(wait),并将当前进程添加到等待队列中(wait),然后将当前进程的状态置为TASK_UNINTERRUPTIBLE,并将等待队列(wait)添加到等待队列头(q)中。之后就被挂起直到资源可以获取,才被从等待队列头(q)中唤醒,从等待队列头中移出。在被挂起等待资源期间,该进程不能被信号唤醒。

(2)sleep_on_timeout()函数:

 

与sleep_on()函数的区别在于调用该函数时,如果在指定的时间内(timeout)没有获得等待的资源就会返回。实际上是调用schedule_timeout()函数实现的。值得注意的是如果所给的睡眠时间(timeout)小于0,则不会睡眠。该函数返回的是真正的睡眠时间。

(3)interruptible_sleep_on()函数:

该函数和sleep_on()函数唯一的区别是将当前进程的状态置为TASK_INTERRUPTINLE,这意味在睡眠如果该进程收到信号则会被唤醒。

(4)interruptible_sleep_on_timeout()函数:

类似于sleep_on_timeout()函数。进程在睡眠中可能在等待的时间没有到达就被信号打断而被唤醒,也可能是等待的时间到达而被唤醒。

Linux 进程等待队列相关推荐

  1. linux 等待进程,Linux 进程等待队列

    Linux内核的等待队列是以双循环链表为基础数据结构,与进程调度机制紧密结合,能够用于实现核心的异步事件通知机制. 在这个链表中,有两种数据结构:等待队列头(wait_queue_head_t)和等待 ...

  2. 【Linux进程、线程、任务调度】二 fork/vfork与写时拷贝 线程的本质 托孤 进程睡眠和等待队列

    学习交流加(可免费帮忙下载CSDN资源): 个人微信: liu1126137994 学习交流资源分享qq群1(已满): 962535112 学习交流资源分享qq群2(已满): 780902027 学习 ...

  3. Linux 进程必知必会

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 只是简单的描述了一下 Linux 基本概念,通过几个例子来 ...

  4. Linux—进程管理

    1. 进程的概念 Linux是一个多用户多任务的操作系统.多用户是指多个用户可以在同一时间使用同一个linux系统:多任务是指在Linux下可以同时执行多个任务,更详细的说,linux采用了分时管理的 ...

  5. Linux进程模型总结

    一个进程在CPU上运行可以有两种运行模式(进程状态):用户模式和内核模式.如果当前运行的是用户程序(用户代码),那么对应进程就处于用户模式(用户态),如果出现系统调用或者发生中断,那么对应进程就处于内 ...

  6. linux 进程调度类型 总结,Linux进程模型总结

    来源于网络 原创不详 Linux进程通过一个task_struct结构体描述,在linux/sched.h中定义,通过理解该结构,可更清楚的理解linux进程模型.   包含进程所有信息的task_s ...

  7. linux查看睡眠进程,关于 Linux 进程的睡眠和唤醒 ,来看这篇就够了~

    1 Linux 进程的睡眠和唤醒 在 Linux 中,仅等待 CPU 时间的进程称为就绪进程,它们被放置在一个运行队列中,一个就绪进程的状 态标志位为 TASK_RUNNING.一旦一个运行中的进程时 ...

  8. linux ps 进程组,linux进程管理(2)---进程的组织结构

    一.目的 linux为了不同的进程管理目的,使用了不同的方法组织进程之间的关系,为了体现父子关系,使用了"树形"图:为了对同一信号量统一处理,使用了进程组:为了快速查找某个进程,使 ...

  9. Linux进程通信的四种方式——共享内存、信号量、无名管道、消息队列|实验、代码、分析、总结

    Linux进程通信的四种方式--共享内存.信号量.无名管道.消息队列|实验.代码.分析.总结 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须 ...

最新文章

  1. nlp文本数据增强_如何使用Texthero为您的NLP项目准备基于文本的数据集
  2. C++、嵌入式软开之指针
  3. 如何释放 DB_RECOVERY_FILE_DEST_SIZE
  4. Silverlight实例教程 - Out of Browser在线更新和Silent安装
  5. Nginx安全说:一剑封喉
  6. Rocketmq原理最佳实践
  7. 我的学习网址(未完)
  8. IJCAI 2019 | 为推荐系统生成高质量的文本解释:基于互注意力机制的多任务学习模型...
  9. 结构动力学MATLAB编程例题,Matlab有限元结构动力学分析与工程应用(源程序)
  10. VMware卸载不干净导致安装VMware报错(无法安装服务vmware Authorization server请确保你有足够的权限)
  11. 多源信息融合研究综述
  12. cad2012打开后闪退_windows7打不开CAD2012出现闪退的处理方法
  13. discuz wooyun-2010-080723
  14. 计算机网络——第四章、网络层
  15. 图解网络(三)——TCP篇07
  16. 不同原因的美团差评,如何回复?
  17. 龙芯 python_html页面转PDF、图片操作记录,Vue项目入门实例
  18. 【MM小贴士】SAP采购订单创建参考采购申请的强控
  19. 多传感器融合定位五-点云地图构建及定位
  20. 股市----别人的经验

热门文章

  1. 【412天】跃迁之路——程序员高效学习方法论探索系列(实验阶段169-2018.03.24)...
  2. wireshark从入门到精通(协议排错安全篇)3
  3. Linux命令——mv
  4. CocoStudio游戏发布后资源加密大致实现思路
  5. 开贴整理QtEmbedded/Qtopia FAQ --- 不可不看的精华都在这里哦[转]
  6. 区块链:游戏规则的改变者
  7. 机器学习--信息 信息熵 信息增益
  8. 如何正确的在项目中接入微信JS-SDK
  9. Javascript 未结束的字符串常量
  10. 【剑指offer】丑数