2嵌入式系统设计实验二(多线程)

上传人:ta****u 文档编号:201413150 上传时间:2023-04-19 格式:DOCX 页数:13 大小:319.63KB
收藏 版权申诉 举报 下载
2嵌入式系统设计实验二(多线程)_第1页
第1页 / 共13页
2嵌入式系统设计实验二(多线程)_第2页
第2页 / 共13页
2嵌入式系统设计实验二(多线程)_第3页
第3页 / 共13页
资源描述:

《2嵌入式系统设计实验二(多线程)》由会员分享,可在线阅读,更多相关《2嵌入式系统设计实验二(多线程)(13页珍藏版)》请在装配图网上搜索。

1、注意实验二是在实验一的基础上完成其内容,具体环境配置见实验一目录实验二 多线程应用程序设计 22.1 实验目的22.2、实验内容22.3、预备知识22.4、实验设备及工具22.5、实验原理及代码分析32.6、实验步骤112.7、思考题13实验二 多线程应用程序设计2.1 实验目的 了解多线程程序设计的基本原理。 学习pthread库函数的使用。2.2、实验内容 读懂pthread.c的源代码,熟悉几个重要的pthread库函数的使用。掌握共享 锁和信号量的使用方法。进入/root/share/exp/basic/02_pthread 目录,运行make 产生pthread程序, 使用 NFS

2、方式连接开发主机进行运行实验。2.3、预备知识 有 C 语言基础 掌握在Linux下常用编辑器的使用 掌握 Makefile 的编写和使用 掌握Linux下的程序编译与交叉编译过程2.4、实验设备及工具 硬件:UP-TECHS2410/P270DVP嵌入式实验平台,PC机Pentium 500以上,硬 盘40G以上,内存大于128M。 软件:PC 机操作系统 REDHAT LINUX 9.0 +MINIC0M + ARM-LINUX 开发环境2.5、实验原理及代码分析1多线程程序的优缺点 多线程程序作为一种多任务、并发的工作方式,有以下的优点: 1)提高应用程序响应。这对图形界面的程序尤其有意

3、义,当一个操作耗时很 长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操 作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线 程,可以避免这种尴尬的情况。 2)使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不 同的线程运行于不同的CPU上。 3) 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个 独立或半独立的运行部分,这样的程序会利于理解和修改。 Libc中的pthread库提供了大量的API函数,为用户编写应用程序提供支持。2实验源代码与结构流程图 本实验为著名的生产者消费者问题模型的实现,主程序中分别启

4、动生产者线 程和消费者线程。生产者线程不断顺序地将0到 1000的数字写入共享的循环 缓冲区,同时消费者线程不断地从共享的循环缓冲区读取数据。流程图如图 2.2.1 所示:本实验具体代码如下:The classic producer-consumer example.Illustrates mutexes and conditions.* by Zou jian guo * 2003-12-22#include #include #include #include pthread.h#define BUFFER_SIZE 16/*设置一个整数的圆形缓冲区*/ struct prodcons i

5、nt bufferBUFFER_SIZE; pthread_mutex_t lock;int readpos, writepos; pthread_cond_t notempty; pthread_cond_t notfull;/*/*初始化缓冲区*/*缓冲区数组*/*互斥锁*/*读写的位置*/*缓冲区非空信号*/*缓冲区非满信号*/*/void init(struct prodcons * b)pthread_mutex_init(&b-lock, NULL); pthread_cond_init (&b-notempty, NULL); pthread_cond_init(&b-notfu

6、ll, NULL); b-readpos = 0;b-writepos = 0;/*/*向缓冲区中写入一个整数*/void put(struct prodcons * b, int data) pthread_mutex_lock(&b-lock);/*等待缓冲区非满*/while (b-writepos + 1) % BUFFER_SIZE = b-readpos) printf(wait for not fulln);pthread_cond_wait (&b-notfull, & b-lock);/*写数据并且指针前移*/b-bufferb-writepos = data;b-write

7、pos+;if (b-writepos = BUFFER_SIZE) b-writepos = 0; /*设置缓冲区非空信号*/pthread_cond_signal( &b-notempty);pthread_mutex_unlock (& b-lock);/*/*从缓冲区中读出一个整数*/int get(struct prodcons * b)int data;pthread_mutex_lock(&b-lock);/*等待缓冲区非空*/while (b-writepos = b-readpos) printf(wait for not emptyn);pthread_cond_wait

8、(&b-notempty, & b-lock);/*读数据并且指针前移*/data = b-bufferb-readpos; b-readpos+;if (b-readpos = BUFFER_SIZE) b-readpos = 0; /*设置缓冲区非满信号*/pthread_cond_signal (& b-notfull);pthread_mutex_unlock (& b-lock);return data;/*/#define OVER (-1)struct prodcons buffer;/*/void * producer(void * data)int n;for (n = 0;

9、 n %dn, n);put (&buffer, n);put (&buffer, OVER);printf(producer stopped!n);return NULL;/*/void * consumer(void * data)int d;while (1) d = get(&buffer);if (d = OVER ) break;printf(”%d-getn, d);printf(consumer stopped!n);return NULL;/*/int main(void)pthread_t th_a, th_b;void * retval;init(&buffer);pth

10、read_create (&th_a, NULL, producer, 0); pthread_create (&th_b, NULL, consumer, 0);/*等待生产者和消费者结束*/ pthread_join(th_a, & retval); pthread_join(th_b, & retval); return 0;3 主要函数分析:下面我们来看一下,生产者写入缓冲区和消费者从缓冲区读数的具体流程,生 产者首先要获得互斥锁,并且判断写指针+1 后是否等于读指针,如果相等则 进入等待状态,等候条件变量not full ;如果不等则向缓冲区中写一个整数, 并且设置条件变量为no t

11、emp ty,最后释放互斥锁。消费者线程与生产者线程 类似,这里就不再过多介绍了。流程图如下:进行生产(put)读取数据设置条件变量notfull释放互斥锁 S图 2.2 生产消费流程图 生产者写入共享的循环缓冲区函数PUTvoid put(struct prodcons * b, int data)pthread_mutex_lock(&b-lock);获取互斥锁while (b-writepos + 1) % BUFFER_SIZE = b-readpos) 如果读写位置相同pthread_cond_wait (&b-notfull, & b-lock);等待状态变量b-notfull,不

12、满则跳出阻塞b-bufferb-writepos = data;写入数据b-writepos+;if (b-writepos = BUFFER_SIZE) b-writepos = 0;pthread_cond_signal (& b-notempty);设置状态变量pthread_mutex_unlock (& b-lock);释放互斥锁 消费者读取共享的循环缓冲区函数GETint get(struct prodcons * b)int data;pthread_mutex_lock(&b-lock);获取互斥锁while (b-writepos = b-readpos) 如果读写位置相同

13、pthread_cond_wait (&b-notempty, & b-lock);等待状态变量b-notempty,不空则跳出阻塞。否则无数据可读。data = b-bufferb-readpos;读取数据b-readpos+;if (b-readpos = BUFFER_SIZE) b-readpos = 0;pthread_cond_signal (& b-notfull);设置状态变量pthread_mutex_unlock (& b-lock);释放互斥锁return data;4 主要的多线程API在本程序的代码中大量的使用了线程函数,如pt hread_cond_signal、p

14、thread_mutex_init、pthread_mutex_lock 等等,这些函数的作用是什么, 在哪里定义的,我们将在下面的内容中为大家做一个简单的介绍,并且为其中 比较重要的函数做一些详细的说明。 线程创建函数:int pthread_create (pthread_t * thread_id, _const pthread_attr_t * _attr,void *(*start routine) (void *),void *restrict arg)获得父进程ID:pthread t pthread self (void) 测试两个线程号是否相同:int pthread equ

15、al (pthread t threadl, pthread t thread2) 线程退出:void pthread exit (void *retval)等待指定的线程结束:int pthread join (pthread t th, void *thread return)互斥量初始化:pthread mutex init (pthread mutex t *,const pthread mutexattr t *) 销毁互斥量:int pthread mutex destroy (pthread mutex t *mutex) 再试一次获得对互斥量的锁定(非阻塞):int pthre

16、ad mutex trylock (pthread mutex t *mutex) 锁定互斥量(阻塞):int pthread mutex lock (pthread mutex t *mutex) 解锁互斥量:int pthread mutex unlock (pthread mutex t *mutex)条件变量初始化:int pthread_cond_init (pthread_cond_t *_restrict _cond, const pthread condattr t *restrict cond attr) 销毁条件变量COND:int pthread_cond_destroy

17、 (pthread_cond_t *cond)A唤醒线程等待条件变量:int pthread_cond_signal (pthread_cond_t *_cond)A等待条件变量(阻塞):int pthread_cond_wait (pthread_cond_t *_restrict _cond, pthread_mutex_t *_restrict _mutex)A在指定的时间到达前等待条件变量:int pthread_cond_timedwait (pthread_cond_t *_restrict _cond,pthread mutex t *restrict mutex, const

18、struct timespec *restrict abstime) PTHREAD库中还有大量的API函数,用户可以参考其他相关书籍。下面我们对 几个比较重要的函数做一下详细的说明: pthread create线程创建函数int pthread_create (pthread_t * thread_id,_const pthread_attr_t * _attr,void *(*start routine) (void *),void *restrict arg) 线程创建函数第一个参数为指向线程标识符的指针,第二个参数用来设置线程 属性,第三个参数是线程运行函数的起始地址,最后一个参数是

19、运行函数的参 数。这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。 第二个参数我们也设为空指针,这样将生成默认属性的线程。当创建线程成功 时,函数返回0若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN 和EINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后者表 示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行 参数三和参数四确定的函数,原来的线程则继续运行下一行代码。丄 pthread join函数用来等待一个线程的结束。函数原型为:int pthread join (pthread t th, void *thread ret

20、urn) 第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可 以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的 函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源 被收回。丄 pthread_exit 函数 一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调 用它的线程也就结束了;另一种方式是通过函数pthread_exit来实现。它的 函数原型为:void pthread exit (void *retval) 唯一的参数是函数的返回代码,只要pt hread_join中的第二个参数 thread_return不是NU

21、LL,这个值将被传递给thread_return。最后要说明的 是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回, 其余调用pthread_join的线程则返回错误代码ESRCH。 下面我们来介绍有关条件变量的内容。使用互斥锁来可实现线程间数据的共享 和通信,互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程 改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被

22、此条件变量阻 塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。一般说来, 条件变量被用来进行线线程间的同步。丄 pthread_cond_init 函数 条件变量的结构为pthread_cond_t,函数pthread_cond_init()被用来初始化一个条件变量。它的原型为:int pthread cond init (pthread cond t * cond, const pthread condattr t * cond attr) 其中cond是一个指向结构pthread_cond_t的指针,cond_attr是一个指向结 构 pthread_condattr_t 的指针

23、。结构 pthread_condattr_t 是条件变量的属性 结构,和互斥锁一样我们可以用它来设置条件变量是进程内可用还是进程间可 用,默认值是PTHREAD_ PROCESS_PRIVATE,即此条件变量被同一进程内的各 个线程使用。注意初始化条件变量只有未被使用时才能重新初始化或被释放。 释放一个条件变量的函数为 pthread_cond_destroy(pthread_cond_tcond)。丄 pthread cond wait函数 使线程阻塞在一个条件变量上。它的函数原型为: extern int pthread_cond_wait (pthread_cond_t *_restri

24、ct_cond, pthread_mutex_t *_restrict _mutex) 线程解开mut ex指向的锁并被条件变量cond阻塞。线程可以被函数 pthread_cond_signal 和函数 pthread_cond_broadcast 唤醒,但是要注意的是,条件变量 只是起阻塞和唤醒线程的作用,具体的判断条件还需用户给出,例如一个变量是否为0等等, 这一点我们从后面的例子中可以看到。线程被唤醒后,它将重新检查判断条件是否满足,如 果还不满足,一般说来线程应该仍阻塞在这里,被等待被下一次唤醒。这个过程一般用while 语句实现。丄 pthread_cond_timedwait 函

25、数 另一个用来阻塞线程的函数是pthread cond timedwait(),它的原型为:extern int pthread_cond_timedwait _P (pthread_cond_t *_cond,pthread mutex t *mutex, const struct timespec *abstime) 它比函数pthread_cond_wait()多了一个时间参数,经历abstime段时间后, 即使条件变量不满足,阻塞也被解除。4 pthread cond signal函数 它的函数原型为: extern int pthread cond signal (pthread c

26、ond t *cond) 它用来释放被阻塞在条件变量cond上的一个线程。多个线程阻塞在此条件变 量上时,哪一个线程被唤醒是由线程的调度策略所决定的。要注意的是,必须 用保护条件变量的互斥锁来保护这个函数,否则条件满足信号又可能在测试条 件和调用 pthread_cond_wait 函数之间被发出,从而造成无限制的等待。2.6、实验步骤1、阅读源代及编译应用程序进入/root/share/exp/basic/02_pthread目录,使用vi编辑器或其他编辑器 阅读理解源代码。运行make产生pthread可执行文件。rootiC rootlS anacqnda-ks.cfg insta I

27、I , l*g rootC IDotlff文件迥骗辑迫)査看(刃磔端 H-iHjfG) ffiWjCHinsta I I . log .log Srreeiisho L .png nni Ji i cotti. I ogiha r ecd share/exp/ba5 ic/root?EC basic? Is 01_lie I Io04_ad02_pttiread 05_da 03_ L tyOfi_ca:nroot?EC basicJS cdO7_ht tpd08_485 09_demDtor 02_pthread/10_kd11_int1 2_pv.mb inCAN kuu ztianexp

28、_carrerakeyboard readniE . txl ke f e k Ru k s . nmk Mkef i leroot?EC 05_pthreatlS I s Mkef l k pthread . c rootiC 02_pthreailS make armr4 l-unknovn- I inux-gee a r mr4 l-unknovn- I inux-gee a r mr4 l-unknowi- I inux-gee root?EC 03_pthreatlS I s-o-o-c -o pthread pthreadi . . /b in/pthread pthread .o

29、 - Ipttiread i pthEsd pthread - IpthreadMke f l k pthread pthread . c root?EC 02_pttireailSpthread图2.3在linux下make多线程2、下切换到minicom终端窗口,先像实验一一样,把串口、网线、电源线接好,配置好2、下切换到minicom终端窗口,先像实验样,把串口、网线、电源线接好,配置好实验箱的IP地址,然后使用NFS mount宿主机(虚拟linux)的/root/share到目标板(实实验箱的IP地址,然后使用NFS mount宿主机(虚拟linux)的/root/share到目标板(实目录进入/host/exp/basic/pthread目录,运行pthread,观察运行结果的正确性。 运行程序最后一部分结果如下:图 2.5 进入/host/exp/basic/pthread 目录 运行 pthread2.7、思考题 1.加入一个新的线程用于处理键盘的输入,并在按键为ESC时终止所有线程。 2.线程的优先级的控制。

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!