

通过生产者与消费者模型感受死锁——西邮本科生的实验
source link: http://mp.weixin.qq.com/s?__biz=MzI3NzA5MzUxNA%3D%3D&%3Bmid=2664607418&%3Bidx=1&%3Bsn=55424b304afafbbdebcdaf48e0371ac2
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一. 实验目的及实验环境
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%正确才是真正的正确,严谨认真、高效简洁是编写代码要有的思维风范。
五.附录:源代码(电子版)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define M 1
#define P(x) sem_wait(&x)
#define V(x) sem_post(&x)
int in = 0;
int out = 0;
int buff[M] = {0};
sem_t sem_dr;
sem_t sem_co;
pthread_mutex_t mutex;
void print()
{
static int number = 0;
int i;
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);
}
}
void sem_mutex_init()
{
int init1 = sem_init(&sem_dr, 0, M);
int init2 = sem_init(&sem_co, 0, 0);
if( (init1 != 0) && (init2 != 0))
{
printf("sem init failed \n");
exit(1);
}
int init3 = pthread_mutex_init(&mutex, NULL);
if(init3 != 0)
{
printf("mutex init failed \n");
exit(1);
}
}
int main()
{
pthread_t id1;
pthread_t id2;
int i;
int ret;
sem_mutex_init(); /*create the producer thread*/
ret = pthread_create(&id1, NULL, producer, NULL);
if(ret != 0)
{
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);
}
Recommend
-
61
共享零售是要围绕家和生活,着力发展互联网能力,赋能线下运营能力
-
75
想要了解更多关于Java生产者消费者问题的演变吗?那就看看这篇文章吧,我们分别用旧方法和新方法来处理这个问题。
-
98
原文地址 前言 在计算机世界当中,数据在不断产生的同时,也在不停地被处理着。产生数据的一方被我们称作生产者,而另一方则被称为消费者。...
-
67
ActiveMQ是Apache所提供的一个开源的消息系统,完全采用Java来实现,因此,它能很好地支持J2EE提出的JMS(Java Message Service,即Java消息服务)规范。JMS是一组Java应用程序接口,它提供消息的创建、发送、读取等一系列服务。JMS提供了一组公共应用程序接口和响...
-
30
前言 不知道大家有没有遇到过这种情况,某个接口的响应时间会随着请求量的变大而越来越慢,明明CPU已经马力全开了怎么还会越来越 慢。又或者是客户端调用http接口,对于客户端来说只是一个入库操作就可以直接返回结果...
-
40
生产者消费者模式是多线程中最为常见的模式:生产者线程(一个或多个)生成面包放进篮子里(集合或数组),同时,消费者线程(一个或多个)从篮子里(集合或数组)取出面包消耗。虽然它们任务不同,但处理的资源是相同的,这体现的是一种线程间通信方式。
-
22
Step 1. 什么是生产者消费者问题 生产者消费者问题也叫 有限缓冲问题 ,是多线程同步的一个最最...
-
29
前言 ······ 一、Kafka的Producer小案例 假设我们现在有一个电商系统,凡是能登录系统的用户都是会员,会员的价值体现在,消费了多少钱,就会累计相应的积分。积分可以兑换礼品包,优惠券···等等。 又到了我们的画图时间👌。首先我们得先来一个订单系
-
23
生产者消费者Java实现
-
8
SpringBoot整合RabbitMQ, 实现生产者与消费者的功能。以及这期间我踩的坑。自然,依赖是少不了的。除了spring-boot-starter-web依赖外。就这个是最主要的依赖了,其他的看着办就是了。我用的是gradle,用maven的看着弄也一样的。无非就是包+包名...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK