首页 > 代码库 > LDD3之并发和竞态-completion(完成量)的学习和验证
LDD3之并发和竞态-completion(完成量)的学习和验证
LDD3之并发和竞态-completion(完成量)的学习和验证
首先说下测试环境:
Linux2.6.32.2
Mini2440开发板
一开始难以理解书上的书面语言,这里《linux中同步例子(完成量completion)》举了一个公交车上司机和乘客的例子还不错,转过来:
这是一个公交司机和售票员之间的线程调度,用于理解完成量,完成量是对信号量的一种补充,主要用于多处理器系统上发生的一种微妙竞争。在这里两个线程间同步,只有当售票员把门关了后,司机才能开动车,只有当司机停车后,售票员才能开门。
如果还是不能够理解就只能反复的调试程序了,现在就把书上的例子使用起来,编译出来completion.ko后进行如下步骤验证
# 1.插入内核模块
insmod completion.ko
# 2.查看申请的次设备号${MINOR}
cat /proc/devices | grep complete
# 3.创建设备节点
mknod /dev/complete c ${MINOR} 0
# 4.首先开启一个终端查看内核信息输出
cat /proc/kmsg
# 5.一个终端读,会睡眠
cat /dev/complete
# 6,另一个终端写
echo /dev/complete
# 7.查看输出
<7>[22050.937732] process 28852 (cat) going to sleep
<7>[22093.994805] process 28866 (bash) awakening the readers...
<7>[22093.994817] awoken 28852 (cat)
下面来验证LDD3上所说的:
1.wait_for_completion
注意wait_for_completion执行会一个非中断的等待,如果没有人来完成该任务,则会产生一个不可杀的进程。
验证:
在运行了cat /dev/complete的时候就已经运行了wait_for_completion,并不运行写程序,看不杀的进程是会不会存在。
通过尝试确实是终止不了。
结论:wait_for_completion等待后如果没人处理任务,那么真的会产生一个不可杀的用户进程,所以这个要小心使用。
2.complete和complete_all
1)complete
在执行第3步(最下)后,只有第2步的cat被唤醒,第1个还在睡眠。
结论:和书的一样。
2)complete_all
分了两种情况来测试:
a.init_completion + complete_all
测试失败!和书上的不照!
b.DECLARE_COMPLETION + complete_all
测试成功!
结论:complete只会唤醒一个等待线程,complete_all会唤醒所有等待线程,前提是静态创建。
3.INIT_COMPLETION
根据书上描述这个是和complet_all配合使用的,那么就测试一下驱动。
结论:使用INIT_COMPLETION进行重新初始化后,完成量可以多次使用。
4.complete_and_exit
1).当内核准备清除该模块时,exit函数会告诉该线程退出并等待completion
这段描述不理解,实验证明一下:
不过看了原型,有点眉目了,这个函数是要添加到exit_xxx函数中的,也就是当没有完成时,是卸载不了的,但是为了卸载可以调用这个函数进行强制完成并卸载。检验一下,直接卸载:
会像图中所示,提示“资源不可用!”。但如果在complete_cleanup中添加complete_and_exit后,同样是“资源不可用!”说明假设失败。
2).决定应用程序的退出码?
同样假设失败,这里填写的是-1,但是应用程序退出码仍然是0.不过有一点是确实可以代替使用!
3).内核多进程中子进程的退出码
驱动群中群主是这样说的。
结论:由于多进程还没有掌握,这个先遗留下来,以后再来补充。
5.wait_for_completion_timeout
结论:不可以被中断,到定时时间无人处理则自行结束。
6.wait_for_completion_interruptible
这个并没有在LDD3中出现,但是很可以就是LDD3中注2中提到的可中断版本.
结论:证实可以被ctrl+c中断,即用户空间的进程可以被杀死!
7.wait_for_completion_interruptible_timeout
结论:10s后如果没有completion则自行中断。
8.wait_for_completion_killable
从源码和实验结果上看不出和wait_for_completion_interruptible有任何区别,代码是前者使用的是TASK_INTERRUPTIBLE后者使用的是 TASK_KILLABLE。
理论上:TASK_NTERRUPTIBLE 睡眠,可以被信号唤醒;TASK_KILLABLE睡眠 只能被致命信号唤醒。
不过现在没有办法区别哪些是致命信号,哪些不是!
9.wait_for_completion_killable_timeout
同样,从源码和实验结果上看不出和wait_for_completion_interruptible_timeout有任何区别,代码是前者使用的是TASK_INTERRUPTIBLE后者使用的是 TASK_KILLABLE。
10.try_wait_for_completion
其返回值始终为0,不知道如何操作才用使其返回值为1.
结论:完全不明白它存在的意义!
11. completion_done
结论:无论有无等待者,判断出来的都是有!进程或者代码中都有把等待信息去掉都无济于事。