第8章 嵌入式Linux多线程编程_第1页
第8章 嵌入式Linux多线程编程_第2页
第8章 嵌入式Linux多线程编程_第3页
第8章 嵌入式Linux多线程编程_第4页
第8章 嵌入式Linux多线程编程_第5页
已阅读5页,还剩35页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 第8章 嵌入式Linux多线程编程 目的要求:了解线程的分类。理解多线程处理机制。掌握Linux线程的概念;多线程编程同步。 重点难点:嵌入式Linux多线程程序的实现.进程与线程(一) 使用多线程的理由之一是和进程相比,它是一种非常节俭的多任务操作方式。 在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种昂贵的多任务工作方式。 而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的

2、时间。 进程与线程(二)使用多线程的理由之二是线程间方便的通信机制。 不同的进程具有独立的数据空间,要进行数据的传递只能通过通信的方式进行 同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用 多线程程序的优点提高应用程序响应。当一个操作耗时很长时,整个系统都会等待这个操作,多线程技术会将耗时长的操作(time consuming)置于一个新的线程。使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分。多线程编程起步编写Linux下的多线程程

3、序,需要使用头文件pthread.h ,连接时需要使用库libpthread.a 多线程程序实例 /* example.c*/#include #include void thread(void)int i;for(i=0;i3;i+)printf(This is a pthread.n); int main(void)pthread_t id;int i,ret;ret=pthread_create(&id,NULL,(void *) thread,NULL);if(ret!=0)printf (Create pthread error!n);exit (1); for(i=0;i3

4、;i+)printf(This is the main process.n);pthread_join(id,NULL);return (0);执行:gcc example.c -lpthread -o example -l参数用于指定编译时要用到的库运行生成的example每次运行的结果可能不同,这是因为两个线程在争夺CPU资源线程标识符 pthread_t pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义:typedef unsigned long int pthread_t;用来标识一个线程主要API函数介绍LIBC中的pthread库提供

5、了大量的API函数在PC机的Linux系统中,其库文件的路径一般是/usr/lib$cd /usr/lib$ls libpthread.*/usr/lib/libpthread.a /usr/lib/libpthread.solibpthread.a 和libpthread.so分别是pthread库的静态和动态链接库文件线程创建函数pthread_create 函数原型:int pthread_create (pthread_t * thread_id, _const pthread_attr_t * _attr, void *(*_start_routine) (void *),void

6、*_restrict _arg) 第一个参数为指向线程标识符的指针 第二个参数用来设置线程属性 第三个参数是线程运行函数的起始地址 最后一个参数是运行函数的参数 函数thread不需要参数,所以最后一个参数设为空指针。第二个参数也设为空指针,这样将生成默认属性的线程。 当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。 创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。pthread_join函数 用来等待一

7、个线程的结束。 函数原型:int pthread_join (pthread_t _th, void *_thread_return)第一个参数为被等待的线程标识符 。第二个参数为一个用户定义的指针,用来存储被等待线程返回值。 这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。 pthread_exit函数一个线程的结束有两种途径,一种是象我们上面的例子,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit实现 。 函数原型:void pthread_exit (void *_retval)唯一的参数是

8、函数的返回代码 。如果pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给 thread_return。 需要注意的是:一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。 线程的属性线程的属性 使用pthread_create函数创建线程时,线程参数一般都为默认值,即将第二个参数设为NULL ,对大多数程序来说,使用默认属性就够了属性结构为pthread_attr_t,它在头文件/usr/include/pthread.h中定义,属性值不能直接设置,须使用相关函数进行操作,初

9、始化的函数为pthread_attr_init,这个函数必须在pthread_create函数之前调用。 线程的优先级 线程的优先级是线程的常用属性, 它存放在结构sched_param中。用函数pthread_attr_getschedparam和函数 pthread_attr_setschedparam进行存放,一般是先取优先级,对取得的值修改后再存放回去。下面是一个简单的例子: #include #include pthread_attr_t attr;pthread_t tid;sched_param param;int newprio=20; pthread_attr_init(&a

10、mp;attr);pthread_attr_getschedparam(&attr, &param);param.sched_priority=newprio;pthread_attr_setschedparam(&attr, &param);pthread_create(&tid, &attr, (void *)myfunction, myarg);互斥锁 互斥锁用来保证一段时间内只有一个线程在执行一段代码 看下面一段代码。这是一个读/写程序,它们公用一个缓冲区,并且假定一个缓冲区只能保存一条信息。即缓冲区只有两个状态:有信息或没有信息。voi

11、d reader_function ( void );void writer_function ( void ); char buffer;int buffer_has_item=0;pthread_mutex_t mutex;struct timespec delay;void main ( void )pthread_t reader;/* 定义延迟时间*/delay.tv_sec = 2;delay.tv_nec = 0;/* 用默认属性初始化一个互斥锁对象*/pthread_mutex_init (&mutex,NULL);pthread_create(&reader,

12、 pthread_attr_default, (void *)&reader_function), NULL);writer_function( ); void writer_function (void)while(1)/* 锁定互斥锁*/pthread_mutex_lock (&mutex);if (buffer_has_item=0)buffer=make_new_item( );buffer_has_item=1;/* 打开互斥锁*/pthread_mutex_unlock(&mutex);pthread_delay_np(&delay); void r

13、eader_function(void)while(1)pthread_mutex_lock(&mutex);if(buffer_has_item=1)consume_item(buffer);buffer_has_item=0;pthread_mutex_unlock(&mutex);pthread_delay_np(&delay);声明互斥锁变量pthread_mutex_t mutex函数 pthread_mutex_init用来生成一个互斥锁。NULL参数表明使用默认属性。 pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthrea

14、d_mutex_unlock为止,均被上锁,即同一时间只能被一个线程调用执行。当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁。在上面的例子中,我们使用了pthread_delay_np函数,让线程睡眠一段时间,就是为了防止一个线程始终占据此函数。 条件变量条件变量 使用互斥锁可实现线程间数据的共享和通信,互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时

15、,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。 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是一

16、个指向结构pthread_condattr_t的指针。结构pthread_condattr_t是条件变量的属性结构 注意:条件变量只有在未被使用时才能重新初始化或被释放。释放一个条件变量的函数为pthread_cond_ destroy(pthread_cond_t cond)。pthread_cond_wait函数 使线程阻塞在一个条件变量上。 函数原型:extern int pthread_cond_wait (pthread_cond_t *_restrict_cond, pthread_mutex_t *_restrict _mutex) 线程解开mutex指向的锁并被条件变量cond

17、阻塞。线程可以被函数pthread_cond_signal和函数pthread_cond_broadcast唤醒 但是要注意的是,条件变量只是起阻塞和唤醒线程的作用,具体的判断条件还需用户给出,例如一个变量是否为0等等, 线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,一般说来线程应该仍阻塞在这里,等待被下一次唤醒。这个过程一般用while语句实现。 pthread_cond_timedwait函数 也可以用来阻塞线程函数原型:extern int pthread_cond_timedwait (pthread_cond_t *_cond, pthread_mutex_t *_mut

18、ex, _const struct timespec *_abstime)它比函数pthread_cond_wait()多了一个时间参数,经历abstime段时间后,即使条件变量不满足,阻塞也被解除。pthread_cond_signal函数 用来释放被阻塞在条件变量cond上的一个线程。 函数原型:extern int pthread_cond_signal (pthread_cond_t *_cond)多个线程阻塞在此条件变量上时,哪一个线程被唤醒是由线程的调度策略所决定的。 使用函数pthread_cond_wait()和函数pthread_cond_signal()的一个简单的例子 p

19、thread_mutex_t count_lock;pthread_cond_t count_nonzero;unsigned count;decrement_count() pthread_mutex_lock (&count_lock);while(count=0) pthread_cond_wait( &count_nonzero, &count_lock);count=count -1;pthread_mutex_unlock (&count_lock);increment_count()pthread_mutex_lock(&count_loc

20、k);if(count=0)pthread_cond_signal(&count_nonzero);count=count+1;pthread_mutex_unlock(&count_lock);count值为0时, decrement函数pthread_cond_wait处被阻塞,并打开互斥锁count_lock。此时,当调用到函数 increment_count时,pthread_cond_signal()函数改变条件变量,告知decrement_count()停止阻塞。 下面我们分析一下著名的生产者消费者问题模型的实现主程序中分别启动生产者线程和消费者线程。生产者线程不断

21、顺序地将0到1000的数字写入共享的循环缓冲区,同时消费者线程不断地从共享的循环缓冲区读取数据。 生产者写入缓冲区和消费者从缓冲区读数的具体流程: 生产者首先要获得互斥锁,并且判断写指针+1后是否等于读指针,如果相等则进入等待状态,等候条件变notfull;如果不等则向缓冲区中写一个整数,并且设置条件变量为notempty,最后释放互斥锁。消费者线程与生产者线程类似 。生产者写入共享的循环缓冲区函数生产者写入共享的循环缓冲区函数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,不满则跳出阻塞。b-bufferb-writepos =

温馨提示

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

评论

0/150

提交评论