您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 能源与动力工程 > 实验二-多线程应用程序设计
信息与通信工程学院实验报告课程名称:嵌入式系统原理与应用实验题目:多线程应用程序设计指导教师:班级:学号:学生姓名:一、实验目的和任务1.掌握VI编译环境。2.掌握GCC编译命令。3.掌握多个文件共同编译方法。4.掌握GDB调试命令。5.了解多线程程序设计的基本原理。6.学习pthread库函数的使用。二、实验设备7.硬件:PC机8.软件:LINUX操作系统、虚拟机三、实验内容及原理1.在VI编辑器里编写两个文件(其中一个为主程序,实现显示“hello,linuxworld,Iam1405014XXXXXX”,,一个为子程序,实现1~n的乘法),为其书写头文件,共同编译为可执行文件,执行,观察运行结果。学习书写MAKEFILE文件,编译,执行,观察结果。利用GCC编译(加参数-g)为可执行文件,利用GDB调试,学习GDB调试命令。2.编写多线程程序设计。编译并运行,观察结果。(可参照课件或实验指导书)成绩四、实验步骤或程序流程1.Gcc编译实验1)编写实验代码:图3.1实验主程序图3.2实验子程序2)编写Makefile文件:图3.3Makefile文件3)Make执行Makefile文件,生成可执行程序并运行:图3.4执行4)Gdb调试运行:图3.5gdb调试显示代码图3.6gdb调试断点运行图3.7gdb调试逐步运行2.多线程程序设计:1)对实验代码进行gcc编译:图3.7gcc编译生成可执行文件2)运行结果:图3.8程序运行结果五、实验数据及程序代码1.Gcc编译实验:1)主程序:#includestdio.h#includemy2.hintmain(){printf(hello.Linuxworld.Iam1405014232zzm\n);my2();}2)实验子程序:#includemy2.h#includestdio.hvoidmy2(){inti=1;floats=1intN;printf(Pleaseinputn:\n);scanf(%d,&N);for(i,i=n,i++)s*=i;printf(result:);printf(%f,s);}3).h头文件:#ifndef_MY2_H#define_MY2_Hintmain();voidmy2();#endif4)makefile执行文件:zzmgo:my2.omy1.ogcc-ozzmgomy2.omy1.omy1.o:my1.cmy2.hgcc-cmy1.cmy2.o:my2.cmy2.hgcc-cmy2.cclean:rm-rfmy1.omy2.ozzmgo1.多线程程序设计:#includestdio.h#includestdlib.h#includetime.h#includepthread.h#defineBUFFER_SIZE16/*Circularbufferofintegers.*/structprodcons{intbuffer[BUFFER_SIZE];/*theactualdata*/pthread_mutex_tlock;/*mutexensuringexclusiveaccesstobuffer*/intreadpos,writepos;/*positionsforreadingandwriting*/pthread_cond_tnotempty;/*signaledwhenbufferisnotempty*/pthread_cond_tnotfull;/*signaledwhenbufferisnotfull*/};/*--------------------------------------------------------*//*Initializeabuffer*/voidinit(structprodcons*b){pthread_mutex_init(&b-lock,NULL);pthread_cond_init(&b-notempty,NULL);pthread_cond_init(&b-notfull,NULL);b-readpos=0;b-writepos=0;}/*--------------------------------------------------------*//*Storeanintegerinthebuffer*/voidput(structprodcons*b,intdata){pthread_mutex_lock(&b-lock);/*Waituntilbufferisnotfull*/while((b-writepos+1)%BUFFER_SIZE==b-readpos){printf(waitfornotfull\n);pthread_cond_wait(&b-notfull,&b-lock);}/*Writethedataandadvancewritepointer*/b-buffer[b-writepos]=data;b-writepos++;if(b-writepos=BUFFER_SIZE)b-writepos=0;/*Signalthatthebufferisnownotempty*/pthread_cond_signal(&b-notempty);pthread_mutex_unlock(&b-lock);}/*--------------------------------------------------------*//*Readandremoveanintegerfromthebuffer*/intget(structprodcons*b){intdata;pthread_mutex_lock(&b-lock);/*Waituntilbufferisnotempty*/while(b-writepos==b-readpos){printf(waitfornotempty\n);pthread_cond_wait(&b-notempty,&b-lock);}/*Readthedataandadvancereadpointer*/data=b-buffer[b-readpos];b-readpos++;if(b-readpos=BUFFER_SIZE)b-readpos=0;/*Signalthatthebufferisnownotfull*/pthread_cond_signal(&b-notfull);pthread_mutex_unlock(&b-lock);returndata;}/*--------------------------------------------------------*/#defineOVER(-1)structprodconsbuffer;/*--------------------------------------------------------*/void*producer(void*data){intn;for(n=0;n1000;n++){printf(put--%d\n,n);put(&buffer,n);}put(&buffer,OVER);printf(producerstopped!\n);returnNULL;}/*--------------------------------------------------------*/void*consumer(void*data){intd;while(1){d=get(&buffer);if(d==OVER)break;printf(%d--get\n,d);}printf(consumerstopped!\n);returnNULL;}/*--------------------------------------------------------*/intmain(void){pthread_tth_a,th_b;void*retval;init(&buffer);pthread_create(&th_a,NULL,producer,0);pthread_create(&th_b,NULL,consumer,0);/*Waituntilproducerandconsumerfinish.*/pthread_join(th_a,&retval);pthread_join(th_b,&retval);return0;}六、实验数据分析及处理1.实验结构流程图:本实验为著名的生产者-消费者问题模型的实现,主程序中分别启动生产者线程和消费者线程。生产者线程不断顺序地将0到1000的数字写入共享的循环缓冲区,同时消费者线程不断地从共享的循环缓冲区读取数据。流程图如图所示:图6.1生产者-消费者实验源代码结构流程图2.主要函数分析:下面我们来看一下,生产者写入缓冲区和消费者从缓冲区读数的具体流程,生产者首先要获得互斥锁,并且判断写指针+1后是否等于读指针,如果相等则进入等待状态,等候条件变量notfull;如果不等则向缓冲区中写一个整数,并且设置条件变量为notempty,最后释放互斥锁。消费者线程与生产者线程类似,这里就不再过多介绍了。流程图如下:图6.2生产消费流程图3.主要的多线程API:在本程序的代码中大量的使用了线程函数,如pthread_cond_signal、pthread_mutex_init、pthread_mutex_lock等等,这些函数的作用是什么,在哪里定义的,我们将在下面的内容中为其中比较重要的函数做一些详细的说明。1)pthread_create线程创建函数:intpthread_create(pthread_t*thread_id,__constpthread_attr_t*__attr,void*(*__start_routine)(void*),void*__restrict__arg)线程创建函数第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空指针,这样将生成默认属性的线程。当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。2)pthread_join函数用来等待一个线程的结束。函数原型为:intpthread_join(pthread_t__th,void**__thread_return)第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。3)pthread_exit函数:一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit来实现。它的函数原型为:voidpthread_exit(void*__retval)唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给thread_return。最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。下面我们来介绍有关条件变量的内容。使用互斥锁来可实现线程间数据的共享和通信,互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法
本文标题:实验二-多线程应用程序设计
链接地址:https://www.777doc.com/doc-6969668 .html