#linux内核之旅#通过生产者与消费者模型感受死锁——西邮本科生的实验
_本文原题:通过生产者与消费者模型感受死锁——西邮本科生的实验
一. 实验目的及实验环境1.实验目的
通过观察、分析实验现象 , 深入理解产生死锁的原因 , 学会分析死锁的方法 ,并利用 pstack、 gdb 或 core 文件分析( valgrind (DRD+Helgrind) 可选 )其中的一 种方法来分析死锁 。
2.实验环境 (1)硬件
CPU:Intel i5
内存:16G
显示器:NVIDIA 1050Ti
硬盘空间:1T
(2)软件
虚拟机名称及版本:VMware
操作系统名称及版本:Ubuntu16.04
编译器:gedit
二. 实验内容1、实验前准备工作
仔细阅读参考资料 Linux 死锁现象及分析方法 , 了解对死锁现象进行分析的各种工具 , 选择其中一种对死锁现象进行分析 。
2、实验内容
1)准备好生产者-消费者问题 , 或者哲学家就餐问题产生死锁的代码 。
2)编译程序后 , 注意加调试选项-g , 先预计一下这个程序的运行结果 , 运行程序 , 若程序没有响应 , 按 ctrl+c 中断程序运行 , 然后再重新运行 , 如此反复若干次 , 记录下每次的运行结果 。 若产生了死锁 , 通过工具对死锁进行分析 。
三、实验结果分析
连续多次查看这个进程的函数调用关系堆栈 , 死锁线程将一直处于等锁状态 , 对比多次的函数调用堆栈输出结果 , 确定哪两个线程(或者几个线程)一直没有变化且一直处于等锁的状态 , 给出运行结果截图 , 在图中标出死锁出现的地方 , 并分析为什么会出现死锁代码设计:假设只有一个生产者 , 却有一个消费者 , 生产者一次生产一个资源 , 消费者一次消耗一个资源 , 按照基本原理应该是先申请资源 , 进而互斥锁上锁 , 若申请失败 , 就不上锁 , 等待申请成功 , 再上锁 。 为了产生死锁条件修改顺序:先互斥锁上锁 , 然后再进行资源申请 。 这样有可能出现生产者未来得及生产资源 , 消费者就进行申请 , 但先上锁后申请 , 所以未申请到 , 不会解锁 , 因为互斥锁未解锁 , 生产者无法生产 。 举个简单的例子(和我组成员刘传玺一同商讨得出):
假设有一个筐子 , 甲做馒头 , 乙吃馒头 , 合理的情况应该是乙看一眼筐里有没有馒头 , 若有 , 则伸手去取 , 若没有 , 则等甲放进去 , 再取;相对应 , 如果做甲看见乙在取馒头 , 此时筐子被占用了 , 甲暂时还不能放馒头进去 , 等乙取完了 ,甲才放新馒头 。 就这样有条不紊一直运行 。 但是现在情况变了 , 乙不管三七二十一伸手就拿 , 要是拿到了还好 , 就吃了 , 要是手快了 , 馒头还没做好 , 他伸手取一抓 , 没抓找 , 手就放在筐子里等 , 甲一看手在筐里放着 , 我馒头也放不进去啊 , 那就等他把手拿出来再放进去... ...一个在等馒头来 , 一个在等手出去:死锁!
发生死锁 , 无资源 , 却申请资源 :
本文插图
进行检查 :
本文插图
锁定错误位置 :
本文插图
互斥锁先锁定后申请资源 , 顺序出错 , 可能会导致死锁 。 发现错误 , 解决错误:
本文插图
四、总结
平时阅读代码 , 觉得一切顺理成章 , 非常自然 , 从未思考为何要这样做 。 通过本次实验 , 老师逆向思维 , 让我们写出死锁!所有代码都在避开死锁 , 老师让我们写出死锁 , 无从下手 , 毫无头绪 , 实在让人头疼 。 查阅资料 , 反复理解运行顺序: 申请 , 上锁 , 释放 , 来来回回 , 费九牛二虎之力才写出死锁 。 回头观望 ,瞬间恍然大悟 , 明白老师了良苦用心 , 躲避错误人人都会 , 但如果我能从无错中犯错 , 也就是说我理解了整个运行结构 , 操作流程之后 , 才能知道在何处会犯错 ,能犯错 , 通过犯错让我们更深刻的体会错误 , 理解错误 。 从而根本的明白错误发生的原因以及修改的方式 。 不得不说实在高明 。 同时我也感受到了 Linux 代码的严谨 , 仅仅是两行代码顺序调换 , 就发生了 意想不到的错误 , 若在大工程中犯错 , 可能会带来毁灭性的后果 。 让我在感叹代码严谨的同时 , 也让我明白了不可以抱有侥幸心理 , 只有错和不错 , 没有可能一说!可能有错那就是错误 , 100%正确才是真正的正确 , 严谨认真、高效简洁是编写代码要有的思维风范 。分页标题
五.附录:源代码(电子版)
intin = 0; intout = 0; intbuff[M] = { 0};
sem_tsem_dr; sem_tsem_co; pthread_mutex_tmutex;
voidprint{ staticintnumber = 0; inti; printf( "(%2d)t",number); for(i = 0; i < M; i++) printf( "%d ", buff[i]); number++; printf( "n"); }
void* producer{ for(;;) { sleep( 1); P(sem_dr); pthread_mutex_lock(&mutex);in = in % M; printf( "(+)produce a product. buffer:"); buff[in] = 1; print; ++in;pthread_mutex_unlock(&mutex); V(sem_co); }}
void* consumer{ for(;;) { sleep( 1); pthread_mutex_lock(&mutex); P(sem_co);out = out % M; printf( "(-)consume a product. buffer:"); buff[out] = 0; print; ++out;pthread_mutex_unlock(&mutex); V(sem_dr); }}
voidsem_mutex_init{ intinit1 = sem_init(&sem_dr, 0, M); intinit2 = sem_init(&sem_co, 0, 0); if( (init1 != 0) && (init2 != 0)) { printf( "sem init failed n"); exit( 1); } intinit3 = pthread_mutex_init(&mutex, NULL); if(init3 != 0) { printf( "mutex init failed n"); exit( 1); } }
intmain{ pthread_tid1; pthread_tid2; inti; intret; sem_mutex_init; /*create the producer thread*/ret = pthread_create(&id1, NULL, producer, NULL); if(ret != 0) { 【#linux内核之旅#通过生产者与消费者模型感受死锁——西邮本科生的实验】printf( "producer creation failed n"); exit( 1); } ret = pthread_create(&id2, NULL, consumer, NULL); if(ret != 0) {printf( "consumer creation failed n"); exit( 1); } pthread_join(id1, NULL); pthread_join(id2, NULL); exit( 0); }
- 新华社|中国重要草原游牧区千余户牧民踏上夏季转场之旅
- 大岭山|东莞微旅游|逛纪念馆,品美食,闻莞香,来趟别样的红色之旅
- 理念|佳通轮胎助力探索之旅,全心守护车主安全
- 自驾|河北青年报&保定金锎至臻奔驰——"驾享夏日"SUV征服之旅完美收官
- 澳大利亚|让您沉“醉”的澳大利亚的会奖之旅
- 三叶草故事家族|【你好!大自然】第151期:到地球的另一端——阿根廷智利之旅(5)
- 清朗读会|‘‘蔷薇花之旅”葡萄酒品鉴会掠影(内附彩蛋)
- 荥阳市妇幼保健院|【创甲之旅】荥阳市妇幼保健院院前急救岗前培训
- 金沙厅|Vlog.杭州 | 一次无计划的治(美)愈(食)之旅
- Luna占星之旅|Lunita2020年6月十二星座月运