linux 3.10中完成量的使用
完成量是基于等待队列设计的,所以显然不能在中断上下文使用完成量。
struct completion {unsigned int done;wait_queue_head_t wait; };
我们来看一个使用完成量的经典例子:
struct kthread_create_info {/* Information passed to kthread() from kthreadd. */int (*threadfn)(void *data);void *data;int node;/* Result passed back to kthread_create() from kthreadd. */struct task_struct *result;struct completion done;struct list_head list; };
在创建内核线程的例子中,我们使用了一个kthread_create_info结构来封装了一个完成量:
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),void *data, int node,const char namefmt[],...) {struct kthread_create_info create;create.threadfn = threadfn;---------------要创建的线程的主函数create.data = data;create.node = node;init_completion(&create.done);------------动态初始化完成量spin_lock(&kthread_create_lock);list_add_tail(&create.list, &kthread_create_list);-------------加入链表,相当于把请求挂在一个双向循环链表中spin_unlock(&kthread_create_lock);wake_up_process(kthreadd_task);-----------唤醒处理完成量的内核线程,来处理我们发送的请求wait_for_completion(&create.done);--------等待完成,这个在等待完成量的期间,会导致本进程睡眠。。。。。。。
如上代码是提交请求的一侧,那么,处理请求的一侧是怎么完成该任务,并通知到请求方呢?
int kthreadd(void *unused) {struct task_struct *tsk = current;/* Setup a clean context for our children to inherit. */set_task_comm(tsk, "kthreadd");ignore_signals(tsk);set_cpus_allowed_ptr(tsk, cpu_all_mask);set_mems_allowed(node_states[N_MEMORY]);current->flags |= PF_NOFREEZE;for (;;) {set_current_state(TASK_INTERRUPTIBLE);if (list_empty(&kthread_create_list))schedule();__set_current_state(TASK_RUNNING);spin_lock(&kthread_create_lock);while (!list_empty(&kthread_create_list)) {struct kthread_create_info *create;create = list_entry(kthread_create_list.next,struct kthread_create_info, list);--------------取出请求list_del_init(&create->list);------------将请求从链表隔离spin_unlock(&kthread_create_lock);-------解锁,这个锁保证加入请求和解除请求的串行化create_kthread(create);------------------创建线程spin_lock(&kthread_create_lock);}spin_unlock(&kthread_create_lock);}return 0; }
简单地看,没看到怎么通知请求方,代码其实是在create_kthread中实现的:
static void create_kthread(struct kthread_create_info *create) {int pid;#ifdef CONFIG_NUMAcurrent->pref_node_fork = create->node; #endif/* We want our own signal handler (we take no signals by default). */pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);if (pid < 0) {create->result = ERR_PTR(pid);complete(&create->done);-------------------通知请求方,一般就是唤醒了} }
以上就是使用完成量的经典例子,两个互不干扰的执行流,一个通过wait_for_completion来等待请求完成,一个通过complete,还有complete_all等来通知请求方,完成交互。
除了动态初始化一个完成量,还有一种静态初始化的方式,
static noinline void __init_refok rest_init(void) {int pid;rcu_scheduler_starting();/** We need to spawn init first so that it obtains pid 1, however* the init task will end up wanting to create kthreads, which, if* we schedule it before we create kthreadd, will OOPS.*/kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);numa_default_policy();pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);------------创建2号进程,也就是kthradd内核线程rcu_read_lock();kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);rcu_read_unlock();complete(&kthreadd_done);------------唤醒被阻塞的进程
在kthreadd 创建之前,
static noinline void __init kernel_init_freeable(void) {/** Wait until kthreadd is all set-up.*/wait_for_completion(&kthreadd_done);
也就是说,在2号进程,也就是 kthreadd 被创建好之前,1号进程其实是阻塞的。有一个疑问就是,为什么1号进程要等待2号进程呢?因为假设1号进程不等待,那么用户态进程就可能通过
系统调用来获取资源,而如果这些资源是由2号线程或者2号线程的子线程来维护的话,则必然产生oops。所以这个地方的完成量,起的是一个时序的作用。
我们可以看到,内核线程的创建接口,是由 kthreadd 内核线程来完成fork的,
ps -ef |grep -i kthreadd root 2 0 0 9月15 ? 00:00:00 [kthreadd]
这个内核线程的pid是2,其他所有的内核线程都是它fork出来的,因为init进程占据了pid 1,所以它的pid是2。
我们假设一下,如果pid 为1的init进程,最终不去执行
if (!run_init_process("/sbin/init") ||!run_init_process("/etc/init") ||!run_init_process("/bin/init") ||!run_init_process("/bin/sh"))
那么它这个时候纯粹还是内核线程,它全部工作在内核态,没有用户态进程的os有没有用呢?
我觉得是有的,没有交互罢了,全部在内核态。恩,如果你把一些任务放在内核里面完成,完全可以不要用户态进程嘛。
转载于:https://www.cnblogs.com/10087622blog/p/9666929.html
linux 3.10中完成量的使用相关推荐
- Linux驱动 - 多线程之 完成量
Linux 系统提供了一种比信号量更好的同步机制,即完成量(completion ,它用于一个执行单元等待另一个 执行单元执行完某事. Linux 系统中与 completion 相关的操作主要有以下 ...
- Linux 4.10中两个新特性与我的一段故事
今早5点半起来没有开始写文章,而是去西湾红树林连跑带走折腾了将近20公里,回来后就8点多了...洗了个澡之后坐稳当,开始写一段关于我的故事. 在2014年到2015年期间,我在负责研发 ...
- win10内核linux,windows 10中发布完整的Linux内核
5月8日消息: 近年来,微软对Linux开发者社区的支持令许多人感到惊讶,包括将诸如Bash shell之类的东西引入到Windows,或者在Windows 10中支持原生OpenSSH,甚至包括Wi ...
- window10内核Linux,windows 10中发布完整的Linux内核
5月8日消息: 近年来,微软对Linux开发者社区的支持令许多人感到惊讶,包括将诸如Bash shell之类的东西引入到Windows,或者在Windows 10中支持原生OpenSSH,甚至包括Wi ...
- 内核并发控制---完成量 (来自网易)
定义在头文件linux/completion.h中; 完成量(completion)是Linux系统提供的一种比信号量更好的同步机制,是对信号量的一种补充;它用于一个执行单元等待另一个执行单元完成某事 ...
- linux内核7大功能,Linux Kernel5.10十个值得关注的功能
Linux Kernel 5.10 有望在本周末发布,外媒 Phoronix 盘点了 10 个值得关注的改进和新功能.5.10 不仅是 2020 年最后一个内核版本,而且还是长期支持(LTS)版本. ...
- 联想 键盘 fn linux,开发者提交补丁,Linux 5.10 或支持联想 PC 键盘快捷键
Linux 5.10 中可能将支持新型号联想 Thinkpad 键盘上的快捷键驱动. 联想 ThinkPad 一直以来对支持 Linux 发行版情有独钟,Fedora.Ubuntu 与 Red Hat ...
- Linux内核中锁机制之完成量、互斥量
在上一篇博文中笔者分析了关于信号量.读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题. 八.完成量 下面讨论完成量的内容,首先需明确完成量表示为一个执行单元需要等 ...
- linux中同步例子(完成量completion)
这是一个公交司机和售票员之间的线程调度,用于理解完成量,完成量是对信号量的一种补充,主要用于多处理器系统上发生的一种微妙竞争 在这里两个线程间同步,只有当售票员把门关了后,司机才能开动车,只有当司机停 ...
最新文章
- 定义一个不能被拷贝的类
- python的span方法_Python Span.set_extension方法代码示例
- InceptionNet V3整理总结
- unity3d双面材质_[转]unity3d中创建双面材质
- 书籍推荐:零基础入门学习Python
- Android8.0 学习 (17)Android国际化(多语言)实现,支持8.0
- poj 1330(LCA)
- 业务gis 怎么让别的开发人员不需要懂gis就可以搞开发? (一)
- 斯坦福大学深度学习公开课cs231n学习笔记(1)softmax函数理解与应用
- hibernate教程笔记10
- Apple Pay的使用
- dimens文件生成器使用方法
- UVALive 4850 Installations——思维
- 伦敦大学国王学院 计算机phd,重磅!伦敦国王学院全奖博士录取一枚!
- Blender软件使用Maps Models Importer插件导入Google地图3d模型(非常简单)
- 字节跳动校招面试题演练
- 简易记账开发笔记之Fragment(前传)
- 数据分析——问卷调查从模型到算法
- 工作4年感想:美团、360、陌陌、百度、阿里、京东面试
- 正面杠腾讯音乐与网易云音乐,抖音与快手谁能“弯道超车“?