您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > UNIX多线程学习笔记
Unix多线程学习笔记Weiming2011-08-05tydic声明:本文档所有内容均为网上整理所得,不保证所有内容正确性.版权属作者本人所有。不用做任何商业用途,仅供广大网友学习交流之用,如有侵权,请联系本人删除,若发现文档中内容有错误或者有个人见解,欢迎指教与相互讨论.Email:.weiming999@foxmail.com。第一节概述多线程程序作为一种多任务、并发的工作方式,有以下的优点1)提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(timeconsuming)置于一个新的线程,可以避免这种尴尬的情况。2)使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。3)改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。线程也有很多缺点1)编写多线程程序需要更全面更升入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性很大。2)调试一个多线程程序比调试一个单线程函数困难得多。Linux下最常用的是遵循POSIX标准的pthread线程库。pthread的实现是通过系统调用clone()这一Linux特有的系统调用来实现。多线程开发涉及的基本概念主要包括三点:线程,互斥锁,条件.其中线程操作操作又分为线程的创建,退出,等待3种.互斥锁则主要包括4种操作,分别是创建,销毁,加锁和解锁.条件操作有5种操作,创建,销毁,触发,广播和等待.其它的一些线程扩展概念,如信号灯等,都可以通过上面的三个基本操作封装处理.线程基础函数列表线程,互斥锁,条件在Linux平台上对应的API可以用表1归纳。为了方便熟悉Windows线程编程的读者熟悉Linux多线程开发的API,我们在表中同时也列出WindowsSDK库中所对应的API名称。表1线程基础函数列表对象操作LinuxPthreadAPWindowsSDK库对应API线程创建pthread_createCreateThread退出pthread_exitThreadExit等待pthread_joinWaitForSingleObject互斥锁创建pthread_mutex_initCreateMutex销毁pthread_mutex_destroyCloseHandle加锁pthread_mutex_lockWaitForSingleObject解锁pthread_mutex_unlockReleaseMutex条件创建pthread_cond_initCreateEvent销毁pthread_cond_destroyCloseHandle触发pthread_cond_signalSetEvent广播pthread_cond_broadcastSetEvent/ResetEvent等待pthread_cond_wait/pthread_cond_timedwaitSingleObjectAndWait第二节线程2.1线程的创建与结束2.1.1)pthread_t线程的标示符类型,pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义typedefunsignedlongintpthread_t;2.1.2)pthread_createintpthread_create(pthread_t*,constpthread_attr_t*,void*(*)(void*),void*);第一个参数为指向线程标识符的指针.第二个参数用了设置线程属性,设置为空指针,这样生成默认属性的线程.第三个参数是线程运行函数的起始地址第四个参数是运行函数的参数.当创建线程成功时,函数返回0,若不为0说明线程创建失败,创建错误返回代码为EAGAIN和EINVAL.前者表示系统限制创建的线程,例如线程数目过多;后者表示第二个参数代表的线程属性值非法,线程创建成功后,新创建的线程运行参数三参数四确定的函数,原来得线程继续运行下一行代码.2.1.3)pthread_join函数pthread_join用来等待一个线程结束.intpthread_join(pthread_t,void**);第一个参数为被等待的线程标识符第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值.这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回.2.1.4)pthread_exit线程除了正常执行结束外,还可通过函数pthread_exit来结束它voidpthread_exit(void*);唯一的参数是函数的返回码,只要pthread_join中得第二个参数不是NULL,这个值将会传递给pthread_join的第二个参数.要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程返回成功,其余调用pthread_join的线程则返回错误ESRCH.2.1.5)pthread_self该函数获取自身线程的ID.pthread_tpthread_self()2.2修改线程的属性线程属性结构为pthread_attr_t,在头文件/usr/include/pthread.h中定义.线程属性初始化函数为pthread_attr_init,这个函数必须在pthread_create函数之前调用.线程属性对象包括是否绑定,是否分离,堆栈大小,优先级.默认属性为非绑定,非分离,缺省1M的堆栈,与父进程同样级别的优先级.线程属性函数有:对线程属性初始化/去除初始化intpthread_attr_destroy(pthread_attr_t*attr);获取/修改线程的分离状态属性intpthread_attr_setdetachstate(pthread_attr_t*attr,intdetachstate);2.2.1)关于线程的绑定线程的绑定,牵扯到另外一个概念,轻进程(LWP:LightWeightProcess).轻进程可以理解为内核进程,它位于用户层和系统层之间,系统对线程资源的分配,对线程的控制是通过轻进程来实现的,一个轻进程可以控制一个或多个线程,启动多少个轻进程,哪些轻进程来控制哪些线程是由系统来控制的,这种状态即称为非绑定的。绑定状况下,则顾名思义,即某个线程固定的绑定到一个轻进程上,被绑定的线程具有较高的响应速度,这是因为cpu时间片的调度是面向轻进程的。绑定的线程可以保证在需要的时候它总有一个轻进程可用。通过设置被绑定的轻进程的优先级和调度级可以使得绑定的线程满足实时反应之类的要求。设置线程绑定状态的函数为pthread_attr_setscope,它有两个参数,第一个时指向属性结构的指针,第二个参数是绑定类型PTHREAD_SCOPE_SYSTEM(绑定的)和PTHREAD_SCOPE_PROCESS(非绑定的)下面的代码即创建一个绑定线程pthread_attr_tattr;pthread_ttid;intpthread_attr_init(pthread_attr_t*attr);intpthread_attr_getdetachstate(constpthread_attr_t*attr,int*detachstate);pthread_attr_init(&attr);/*初始化属性值,均设为默认值*/pthread_attr_setscope(&attr,PTHREAD_SCOPE_SYSTEM);pthread_create(&tid,&attr,(void*)my_function,NULL);2.2.2)关于线程的状态:分离态/非分离态线程的分离状态决定一个线程以什么样的方式来终止自己,在上面的例子中,我们采用了线程的默认属性,即非分离状态,在这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的资源。而分离线程不是这样的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放资源。应该根据自己的需要,选择合适的分离状态。设置线程分离状态的函数:pthread_attr_setdetachstate(pthread_attr_t*attr,intdetachstate)第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和PTHREAD_CREAE_JOINABLE(非分离线程)这里要主要的一点,如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在pthread_create函数返回之前就终止了,它终止后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用pthread_cond_timewait函数,让这个线程等待一会,留出足够的时间让函数pthread_create返回。设置一段等待时间,是再多线程编程里常用的方法,都是注意不要使用诸如wait()之类的函数,他们是使整个进程睡眠,并不能解决线程同步的问题.使线程进入分离状态也可用如下函数intpthread_detach(pthread_ttid);2.2.3)关于线程的优先级线程的优先级,它存放在结构sched_param中,用函数pthread_attr_getschedparam和函数pthread_attr_setschedparam进行关联,一般来说,我们总是先取出优先级,对取得的值修改后再放回去。线程的优先级取值范围为-20—20,值越大,其优先级越低,缺省值为0,这个参数仅当调度策略为实时(SCHED_RR或SCHED_FIFO)时才有效。通过pthread_setschedparam()函数来改变pthread_attr_tattr;pthread_ttid;sched_paramparam;intnewprio=20;pthtead_attr_init(attr);pthread_attr_getschedparam(&attr,param);param.sched_priority=newprio;pthread_attr_setschedparam(&attr,param);pthrad_create(&tid,&attr,(void*)myfunction,myarg);第三节互斥锁互斥锁是用来保证一段时间内只有一个线程在执行一段代码pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,即同一时间只能被一个线程调用执行。当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁。A线程先锁定互斥锁1,B线程先锁定互斥锁2,这是就出现了死锁。此时我们可以使用函数pthread_mutex_trylock,它是函数pthread_mutex_lock的非阻塞版本,当它发现死锁不可避免时,它会返回相应的信息,程序员可以针对死锁做出相应的处理。另外不同的互斥锁类型对死锁的处理不一样,但最主要的还是要程序员自己在程序设计时注意这一点。pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待互斥锁函数有:初始化一个互斥量intpthread_mutex_init(pthread_mutex_t*mutex,constpthread_mutexattr_t*attr);给一个互斥量加锁intpthread_mutex_lock(pthread_
本文标题:UNIX多线程学习笔记
链接地址:https://www.777doc.com/doc-3368383 .html