《Step by StepLinux C多线程编程入门(基本API及多线程.pdf》由会员分享,可在线阅读,更多相关《Step by StepLinux C多线程编程入门(基本API及多线程.pdf(9页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、介绍:什么是线程,线程的优点是什么介绍:什么是线程,线程的优点是什么线程在Unix系统下,通常被称为轻级的进程,线程虽然是进程,但却可以看作是Unix进程的表亲,同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈有各自的调用栈(callstack),自己的寄存器环境(,自己的寄存器环境(registercontext),自己的线程,自己的线程本地存储本地存储(threadlocalstorage)。一个进程可以有很多线程,每条线程并行执行同的任务。线
2、程可以提高应用程序在多核环境下处理诸如文件I/O或者socketI/O等会产生堵塞的情况的表现性能。在Unix系统中,一个进程包含很多东西,包括可执行程序以及一大堆的诸如文件描述符地址空间等资源。在很多情况下,完成相关任务的同代码间需要交换数据。如果采用多进程的方式,那么通信就需要在用户空间和内核空间进行频繁的切换,开销很大。但是如果使用多线程的方式,因为可以使用共享的全局变,所以线程间的通信(数据交换)变得非常高效。HelloWorld(线程创建、结束、等待)线程创建、结束、等待)创建线程创建线程pthread_create线程创建函数包含四个变,分别为:1.一个线程变名,被创建线程的标识2
3、.线程的属性指针,缺省为NULL即可3.被创建线程的程序代码4.程序代码的参数Forexample:pthread_tthrd1pthread_attr_tattrvoidthread_function(voidargument)char*some_argumentpthread_create(&thrd1,NULL,(void*)&thread_function,(void*)&some_argument);结束线程结束线程pthread_exit线程结束调用实例:pthread_exit(void*retval);/retval用于存放线程结束的退出状态线程等待线程等待pthread_jo
4、inpthread_create调用成功以后,新线程和线程谁先执行,谁后执行用户是知道的,这一块取决与操作系统对线程的调度,如果我们需要等待指定线程结束,需要使用pthread_join函数,这个函数实际上类似与多进程编程中的waitpid。举个例子,以下假设A线程调用pthread_join试图去操作B线程,该函数将A线程阻塞,直到B线程退出,当B线程退出以后,A线程会收集B线程的返回码。该函数包含两个参数:pthread_tth/th是要等待结束的线程的标识void*thread_return/指针thread_return指向的位置存放的是终止线程的返回状态。调用实例:pthread_j
5、oin(thrd1,NULL);example1:1 /*2 F i l e N a m e:t h r e a d _ h e l l o _ w o r l d.c 3 A u t h o r:c o u l d t t(f y b y)4 M a i l:f u y u n b i y i g m a i l.c o m 5 C r e a t e d T i m e:2 0 1 3 1 2 月1 4 日 星期六 1 1 时4 8 分5 0 秒 6 */7 8#i n c l u d e 9#i n c l u d e 1 0#i n c l u d e 1 1 1 2 v o i d
6、p r i n t _ m e s s a g e _ f u n c t i o n (v o i d *p t r)1 3 1 4 i n t m a i n()1 5 1 6 i n t t m p 1,t m p 2 1 7 v o i d *r e t v a l 1 8 p t h r e a d _ t t h r e a d 1,t h r e a d 2 1 9 c h a r *m e s s a g e 1 =t h r e a d 1 2 0 c h a r *m e s s a g e 2 =t h r e a d 2 2 1 2 2 i n t r e t _ t
7、h r d 1,r e t _ t h r d 2 2 3 2 4 r e t _ t h r d 1 =p t h r e a d _ c r e a t e(&t h r e a d 1,N U L L,(v o i d *)&p r i n t _ m e s s a g e _ f u n c t i o n,(v o i d*)m e s s a g e 1)2 5 r e t _ t h r d 2 =p t h r e a d _ c r e a t e(&t h r e a d 2,N U L L,(v o i d *)&p r i n t _ m e s s a g e _
8、f u n c t i o n,(v o i d*)m e s s a g e 2)2 6 2 7 /线程创建成功,返回0,失败返回失败号2 8 i f (r e t _ t h r d 1 !=0)2 9 p r i n t f(线程1 创建失败 n )3 0 e l s e 3 1 p r i n t f(线程1 创建成功 n )3 2 3 3 3 4 i f (r e t _ t h r d 2 !=0)3 5 p r i n t f(线程2 创建失败 n )3 6 e l s e 3 7 p r i n t f(线程2 创建成功 n )3 8 3 9 4 0 /同样,p t h r e
9、 a d _ j o i n 的返回值成功为04 1 t m p 1 =p t h r e a d _ j o i n(t h r e a d 1,&r e t v a l)4 2 p r i n t f(t h r e a d 1 r e t u r n v a l u e(r e t v a l)i s%d n ,(i n t)r e t v a l)4 3 p r i n t f(t h r e a d 1 r e t u r n v a l u e(t m p)i s%d n ,t m p 1)4 4 i f (t m p 1 !=0)4 5 p r i n t f(c a n n o
10、 t j o i n w i t h t h r e a d 1 n )4 6 4 7 p r i n t f(t h r e a d 1 e n d n )4 8 4 9 t m p 2 =p t h r e a d _ j o i n(t h r e a d 1,&r e t v a l)5 0 p r i n t f(t h r e a d 2 r e t u r n v a l u e(r e t v a l)i s%d n ,(i n t)r e t v a l)5 1 p r i n t f(t h r e a d 2 r e t u r n v a l u e(t m p)i s
11、%d n ,t m p 1)5 2 i f (t m p 2 !=0)5 3 p r i n t f(c a n n o t j o i n w i t h t h r e a d 2 n )5 4 5 5 p r i n t f(t h r e a d 2 e n d n )5 6 5 7 5 8 5 9 v o i d p r i n t _ m e s s a g e _ f u n c t i o n(v o i d *p t r )6 0 i n t i =0 6 1 f o r (i i F i l e N a m e:n o _ m u t e x.c 3 A u t h o r
12、:c o u l d t t(f y b y)4 M a i l:f u y u n b i y i g m a i l.c o m 5 C r e a t e d T i m e:2 0 1 3 1 2 月1 5 日 星期日 1 7 时5 2 分2 4 秒 6 */7 8#i n c l u d e 9#i n c l u d e 1 0#i n c l u d e 1 1 1 2 i n t s h a r e d i =0 1 3 v o i d i n c r e s e _ n u m(v o i d)1 4 1 5 i n t m a i n()1 6 i n t r e t 1
13、7 p t h r e a d _ t t h r d 1,t h r d 2,t h r d 3 1 8 1 9 r e t =p t h r e a d _ c r e a t e(&t h r d 1,N U L L,(v o i d *)i n c r e s e _ n u m,N U L L)2 0 r e t =p t h r e a d _ c r e a t e(&t h r d 2,N U L L,(v o i d *)i n c r e s e _ n u m,N U L L)2 1 r e t =p t h r e a d _ c r e a t e(&t h r d
14、3,N U L L,(v o i d *)i n c r e s e _ n u m,N U L L)2 2 2 3 p t h r e a d _ j o i n(t h r d 1,N U L L)2 4 p t h r e a d _ j o i n(t h r d 2,N U L L)2 5 p t h r e a d _ j o i n(t h r d 3,N U L L)2 6 2 7 p r i n t f(s h a r e d i =%d n ,s h a r e d i)2 8 2 9 r e t u r n 0 3 0 3 1 3 2 3 3 v o i d i n c
15、r e s e _ n u m(v o i d)3 4 l o n g i,t m p 3 5 f o r(i=0 i F i l e N a m e:m u t e x.c 3 A u t h o r:c o u l d t t(f y b y)4 M a i l:f u y u n b i y i g m a i l.c o m 5 C r e a t e d T i m e:2 0 1 3 1 2 月1 5 日 星期日 1 7 时5 2 分2 4 秒 6 */7 8#i n c l u d e 9#i n c l u d e 1 0#i n c l u d e 1 1 1 2 i n t
16、 s h a r e d i =0 1 3 v o i d i n c r e s e _ n u m(v o i d)1 4 1 5 p t h r e a d _ m u t e x _ t m u t e x =P T H R E A D _ M U T E X _ I N I T I A L I Z E R 1 6 1 7 i n t m a i n()1 8 i n t r e t 1 9 p t h r e a d _ t t h r d 1,t h r d 2,t h r d 3 2 0 2 1 r e t =p t h r e a d _ c r e a t e(&t h r
17、d 1,N U L L,(v o i d *)i n c r e s e _ n u m,N U L L)2 2 r e t =p t h r e a d _ c r e a t e(&t h r d 2,N U L L,(v o i d *)i n c r e s e _ n u m,N U L L)2 3 r e t =p t h r e a d _ c r e a t e(&t h r d 3,N U L L,(v o i d *)i n c r e s e _ n u m,N U L L)2 4 2 5 p t h r e a d _ j o i n(t h r d 1,N U L L
18、)2 6 p t h r e a d _ j o i n(t h r d 2,N U L L)2 7 p t h r e a d _ j o i n(t h r d 3,N U L L)2 8 2 9 p r i n t f(s h a r e d i =%d n ,s h a r e d i)3 0 3 1 r e t u r n 0 3 2 3 3 3 4 3 5 v o i d i n c r e s e _ n u m(v o i d)3 6 l o n g i,t m p 3 7 f o r(i=0 i =1 0 0 0 0 0 i+)3 8 /*加锁*/3 9 i f (p t h
19、 r e a d _ m u t e x _ l o c k(&m u t e x)!=0)4 0 p e r r o r(p t h r e a d _ m u t e x _ l o c k )4 1 e x i t(E X I T _ F A I L U R E)4 2 4 3 t m p =s h a r e d i 4 4 t m p =t m p +1 4 5 s h a r e d i =t m p 4 6 /*解锁锁*/4 7 i f (p t h r e a d _ m u t e x _ u n l o c k(&m u t e x)!=0)4 8 p e r r o r(
20、p t h r e a d _ m u t e x _ u n l o c k )4 9 e x i t(E X I T _ F A I L U R E)5 0 5 1 5 2 结果分析结果分析这一次,我们的结果是正确的,锁有效得保护我们的数据安全。然而:1.锁保护的并是我们的共享变(或者说是共享内存),对于共享的内存而言,用户是无法直接对锁保护的并是我们的共享变(或者说是共享内存),对于共享的内存而言,用户是无法直接对其保护的,因为那是物理内存,无法阻止其他程序的代码访问。事实上,锁之所以对关键区域进行其保护的,因为那是物理内存,无法阻止其他程序的代码访问。事实上,锁之所以对关键区域进行保护
21、,在本例中,是因为所有线程都遵循一个规则,那就是在进入关键区域钱加保护,在本例中,是因为所有线程都遵循一个规则,那就是在进入关键区域钱加同一把同一把锁,在锁,在退出关键区域钱释放退出关键区域钱释放同一把同一把锁锁2.我们从上述运行结果中可以看到,加锁是会带来额外的开销的,加锁的代码其运行速度,明显比我们从上述运行结果中可以看到,加锁是会带来额外的开销的,加锁的代码其运行速度,明显比加锁的要慢一些,所以,在使用锁的时候,要合理,在需要对关键区域进行保护的场景下,我们加锁的要慢一些,所以,在使用锁的时候,要合理,在需要对关键区域进行保护的场景下,我们便要画蛇添足,为其加锁便要画蛇添足,为其加锁方式
22、二:信号方式二:信号锁有一个很明显的缺点,那就是它只有两种状态:锁定与锁定。信号本质上是一个非负数的整数计数器,它也被用来控制对公共资源的访问。当公共资源增加的时候,调用信号增加函数sem_post()对其进行增加,当公共资源减少的时候,调用函数sem_wait()来减少信号。其实,我们是可以把锁当作一个01信号的。它们是在/usr/include/semaphore.h中进行定义的,信号的数据结构为sem_t,本质上,它是一个long型整数相关函数相关函数在使用semaphore之前,我们需要先引入头文件#include 初始化信号:int sem_init(sem_t*sem,int ps
23、hared,unsigned int value);成功返回0,失败返回1参数sem:指向信号结构的一个指针pshared:是0的时候,该信号在进程间共享,否则只能为当前进程的所有线程们共享value:信号的初始值信号减1操作,当sem=0的时候该函数会堵塞int sem_wait(sem_t*sem);成功返回0,失败返回1参数sem:指向信号的一个指针信号加1操作int sem_post(sem_t*sem);参数与返回同上销毁信号int sem_destroy(sem_t*sem);参数与返回同上代码示例代码示例 1 /*2 F i l e N a m e:s e m.c 3 A u t
24、 h o r:c o u l d t t(f y b y)4 M a i l:f u y u n b i y i g m a i l.c o m 5 C r e a t e d T i m e:2 0 1 3 1 2 月1 5 日 星期日 1 9 时2 5 分0 8 秒 6 */7 8#i n c l u d e 9#i n c l u d e 1 0#i n c l u d e 1 1#i n c l u d e 1 2 1 3#d e f i n e M A X S I Z E 1 01 4 1 5 i n t s t a c k M A X S I Z E 1 6 i n t s i z
25、 e =0 1 7 s e m _ t s e m 1 8 1 9 /生产者2 0 v o i d p r o v i d e _ d a t a(v o i d)2 1 i n t i 2 2 f o r (i=0 i M A X S I Z E i+)2 3 s t a c k i =i 2 4 s e m _ p o s t(&s e m)/为信号加12 5 2 6 2 7 2 8 /消费者2 9 v o i d h a n d l e _ d a t a(v o i d)3 0 i n t i 3 1 w h i l e(i =s i z e+)M A X S I Z E)3 2 s
26、e m _ w a i t(&s e m)3 3 p r i n t f(乘法:%d X%d =%d n ,s t a c k i ,s t a c k i ,s t a c k i *s t a c k i )3 4 s l e e p(1)3 5 3 6 3 7 3 8 i n t m a i n(v o i d)3 9 4 0 p t h r e a d _ t p r o v i d e r,h a n d l e r 4 1 4 2 s e m _ i n i t(&s e m,0,0)/信号初始化4 3 p t h r e a d _ c r e a t e(&p r o v i
27、d e r,N U L L,(v o i d *)h a n d l e _ d a t a,N U L L)4 4 p t h r e a d _ c r e a t e(&h a n d l e r,N U L L,(v o i d *)p r o v i d e _ d a t a,N U L L)4 5 p t h r e a d _ j o i n(p r o v i d e r,N U L L)4 6 p t h r e a d _ j o i n(h a n d l e r,N U L L)4 7 s e m _ d e s t r o y(&s e m)/销毁信号4 8 4 9 r e t u r n 0 5 0 运行结果:运行结果:因为信号机制的存在,所以代码在handle_data的时候,如果sem_wait(&sem)时,sem为0,那么代码会堵塞在sem_wait上面,从而避免在stack中访问错误的index而使整个程序崩溃。