linux线程
线程的优势
创建线程花费的代价,比创建进程小得多,所以同一个进程的,多个线程执行多个任务——>比多个进程执行多个任务更有效率。
线程分类
线程也分为用户级线程、内核级线程——对于前者,多个线程之间的上下文切换,由用户决定;对于后者,则由系统决定。(二者一般是1:1或者1:n的对应关系)
线程共享资源
于同一进程的多个线程共享同一地址空间,所以代码段,数据段是共享的,如果定义一个函数(存储在代码段),各线程都可以进行调用,如果定义个全局变量(存储在数据段),在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:
1.文件描述符表
2.每种信号的处理方式(SIG_IGN,SIG_DFL,用户自定义)
3.当前工作目录
4.用户id和组id
线程独享资源
但有些资源是线程独享的:
1.线程id
2.上下文,包括各种寄存器的值,程序计数器和栈指针
3.栈空间
4.errno变量
5.信号屏蔽字
6.调度优先级
线程编译
多线程程序的编译时,一定记得要加入动态库,例如:gcc k.c -o k -lpthread,但运行时却不用加。
线程编码
编码是首先需要应用线程库#include <pthread.h>。
线程的创建:int pthread_create(&线程名字,NULL,线程执行函数名,传递的参数*arg),执行函数必须是这种:void *func(),可以带参数,也可以不带,函数体随意。成功则返回0。
线程的退出:void pthread_exit(void *returnValue),返回值就是一个字符串,可以由其他函数,如等待函数pthread_join来检测获取其返回值。
线程等待:int pthread_join(pthread_t thread,void **retval);成功返回0,失败返回错误号。 线程的等待是以阻塞式等待,线程不等待会产生内存泄露(类似进程的僵尸进程)
进程取消:在合理范围内,线程可以自我或者被别人取消。取消后返回PTHREAD_CANCELED(它被定义为(void *)-1),取消调用函数pthread_cancel(id);
线程分离:在任何一个时间点上线程是可结合的(joinable)或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死。在被其他线程回收之前,它的存储器资源(例如栈)是不释放的。相反一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终时时由系统自动释放。 默认情况一个线程是可结合的,每一个可结合的线程都应该被显性的回收,既调用pthread_join()函数,分离调用函数pthread_detach。分离的这个函数是非阻塞的,可以立即返回。但为什么要分离呢?因为主进程在处理线程时,要处理不止一个,而每一个都需要被等待,然而join是阻塞式的,这样的话就只能处理一个线程,所以要加入分离,这样就可以处理多个线程。调用pthread_detach()后,这些子进程的状态会被设置为分离的,该线程运行结束会自动释放所有资源。
线程的分离和合并都是为了解决内存泄漏的问题,只是不同的场景选择不同的方案而已,线程创建时默认是joinable状态没如果不显示join阻塞调用或设置分离状态,即便线程结束返回或者pthread_exit时都不会释放线程所占用堆栈和线程描述符,造成资源泄露。
线程是有属性的,这个属性由一个线程属性对象来描述。线程属性对象由pthread_attr_init()接口初始化,并由pthread_attr_destory()来销毁,它们的完整定义是:
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destory(pthread_attr_t *attr);
Linux下的线程有:绑定属性、分离属性、调度属性、堆栈大小属性和满占警戒区大小属性。
线程同步
互斥锁:Linux初始化和销毁互斥锁的接口是pthread_mutex_init()和pthead_mutex_destroy(),对于加锁和解锁则有pthread_mutex_lock()、pthread_mutex_trylock()和pthread_mutex_unlock()。
条件变量:初始化和销毁条件变量的接口是pthread_cond_init()和pthread_cond_destory();控制“事件”发生的接口是pthread_cond_signal()或pthread_cond_broadcast();等待“事件”发生的接口是pthead_cond_wait()或pthread_cond_timedwait()。条件变量在通知和等待使用时需要搭配互斥锁使用。
信号量:PV操作