一 线程(也称为轻量级的进程)
1.1、线程基本特点
a)线程依赖于进程而存在,在一个进程里面开出的多个线程共享同一进程空间,这样利用多线程实现多任务时,就能避免因为大量频繁的进程间切换而带来的开销。
b)每个线程也同样有一个task_truct结构体来描述,但是共享同一进程的所有线程共享入口地址
c)进程与线程都参与统一的内核调度(切换)。
d)线程的本质就是指针函数。
1.2、线程好处
1)大大提高了进程间的切换效率
2)避免了不必要的TLB和cache刷新,节省了空间的消耗
1.3、线程的实现
1)不由内核实现,而是由第三方线程库实现的,编译时需要连接才行
2)同一进程内的所有线程都会共享进程的哪些资源呢?
a)指令代码
b)静态数据(主要是用于线程间通信用的全局变量)
c)进程打开的所有的文件描述符
d)进程的当前工作目录
e)进程的实际用户ID和有效用户ID
f)实际组ID和有效组ID
3)每个线程的私有资源有哪些?
a)线程ID(TID)
b)自己的PC(程序计数器值)和相关的状态寄存器(存放该线程被切换时的状态)
c)自己的局部变量(每个线程其实就是一个函数),每个线程都会从进程栈中开出自己的
线程栈(也可称为线程函数栈)
d)自己的错误号errno
e)自己的信号掩码(屏蔽字,起初是继承进程(主线程)的),和未决信号集(继承于主线程,但是会被立即清空)
f)有自己的执行状态
4)线程实现过程
a)创建线程,pthread_create函数
b)控制线程,pthread_join,pthread_detach,pthread_cancle,pthread_exit等函数
5)线程的资源保护
我们知道,对于进程来说资源保护是天然的,因为它们拥有独立虚拟内存空间,互相不能互访,这也导致相互通信也很不容易。但是对于同一进程内的多个线程来说,由于它们共享进程的虚拟内存地址,因此它们相互之间可以很容易地进行资源的共享,但是资源间的保护却成为了一个问题。线程资源保护机制有:
a)无名信号量(进程用的是有名信号量或称为系统V信号量)
b)线程间的互斥锁
c)条件变量(一种线程间的异步通信机制,类似于进程间的信号通信)
6)注意,如果主线程先死,那么所有次线程都会跟着死调,所以任何线程调了exit函数后整个进程将会结束
二 线程与进程
进程是程序执行时的一个实例,即它是程序已经执行到何种程度的数据结构的汇集。从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位。
线程是进程的一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程由几个线程组成(拥有很多相对独立的执行流的用户程序共享应用程序的大部分数据结构),线程与同属一个进程的其他的线程共享进程所拥有的全部资源。
"进程——资源分配的最小单位,线程——程序执行的最小单位"
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
具体异同看下表:
三 相关函数
线程创建函数
intpthread_create(pthread_t*thread,constpthread_attr_t*attr,
void*(*start_routine)(void*),void*arg);
线程等待函数:阻塞等待线程结束,结束后由主回收线程的资源
intpthread_join(pthread_tthread,void**retval);
线程分离函数:分离后,资源在线程结束时自己释放,不有主线程回收
intpthread_detach(pthread_tthread);//这个函数和pthread_join二者只能有一个被用
主动取消线程函数
int pthread_cancel(pthread_tthread);·取消是否是使能设置函数:默认情况是使能
线程属性设置函数
线程属性有哪些:
a)绑定属性:用户线程和内核服务线程是否绑定(default:非绑定),cpu时间片的调度是面向内核线程实现的
b)分离属性:线程结束时,线程资源由谁回收,设置了分离,就由自己释放,未设置分离,资
源由等待线程(join函数等待)回收,(default:非分离),分离属性也可由前
面的pthread_detach函数来设置
c)堆栈的地址和堆栈的大小:线程的堆栈其实就是函数的堆栈,是从进程的堆栈中刮分出来的,
默认情况下,线程具体的堆栈地址由内核决定,堆栈大小默认1M,当然我也可以认为的更改它
d)线程的优先级:由于线程是与它的生父进程(主线程)一样统一地参与内核的
调度器的调度,所以存在着调度优先级的问题,默认情况是他和生父进程有着同样的优先级别
e)一般情况下,我们都采用默认设置即可
线程属性设置函数
a)线程属性初始化函数
intpthread_attr_init(pthread_attr_t*attr);
b)线程属性删除函数:删除为属性设置,恢复内核原有默认的属性设置,
防止永远的穿改了默认的属性设置
intpthread_attr_destroy(pthread_attr_t*attr);c)设置绑定函数
intpthread_attr_setscope(pthread_attr_t*attr,intscope);//设置intpthread_attr_getscope(pthread_attr_t*attr,int*scope);//获取
d)设置分离属性
intpthread_attr_setdetachstate(pthread_attr_t*attr,intdetachstate);//设置
intpthread_attr_getdetachstate(pthread_attr_t*attr,int*detachstate);//获取
e)设置堆栈属性
/*设置*/
intpthread_attr_setstack(pthread_attr_t*attr,void*stackaddr,size_tstacksize)
/*获取*/intpthread_attr_getstack(pthread_attr_t*attr,void**stackaddr,size_t*stacksize)
f)设置优先级属性
/*设置*/
intpthread_attr_setschedparam(pthread_attr_t*attr,conststructsched_param*param);
/*获取*/
intpthread_attr_getschedparam(pthread_attr_t*attr,structsched_param*param);
设置互斥锁相关的函数
互斥锁初始化函数
intpthread_mutex_init(pthread_mutex_t*restrictmutex,constpthread_mutexattr_t*restrictattr);
互斥锁直接初始化,只能初始化,不能赋值,因为pthread_mutex_t是结构体类型
pthread_mutex_tmutex=PTHREAD_MUTEX_INITIALIZER;
互斥锁销毁函数
intpthread_mutex_destroy(pthread_mutex_t*mutex);
加锁解锁函数
阻塞解锁:intpthread_mutex_lock(pthread_mutex_t*mutex);
非阻塞加锁:intpthread_mutex_trylock(pthread_mutex_t*mutex);·解锁:intpthread_mutex_unlock(pthread_mutex_t*mutex);
互斥锁属性设置函数
·互斥锁属性初始化和删除
/*属性初始化*/
intpthread_mutexattr_init(pthread_mutexattr_t*attr);/*互斥所属性删除:类似线程的属性删除*/
intpthread_mutexattr_destroy(pthread_mutexattr_t*attr);
互斥锁类型设置和获取
互斥锁类型分类:
PTHREAD_MUTEX_DEFAULT:快速互斥锁(或叫阻塞互斥锁),默认此种锁,统一把锁,不能多次加锁,已经解开了的锁也不能再次解锁,这些都会出错返回
PTHREAD_MUTEX_ERRORCHECK:检错互斥锁,快速互斥锁的费阻塞版本
PTHREAD_MUTEX_RECURSIVE:递归互斥锁,同一把锁可多次枷锁,每加一次锁,锁的连接计数加1,解锁时的解锁顺序与加锁顺序相反,每解一次连接技术减1,加过多少次锁,就必须接多少次
intpthread_mutexattr_settype(pthread_mutexattr_t*attr,inttype);//设置
intpthread_mutexattr_gettype(constpthread_mutexattr_t*restrictattr,int*restricttype);//获取
设置线程信号量相关的函数
初始化函数
intsem_init(sem_t*sem,intpshared,unsignedintvalue);
删除函数
intsem_destroy(sem_t*sem);
P操作:等资源
intsem_wait(sem_t*sem);//阻塞等待资源
intsem_trywait(sem_t*sem);//非阻塞等待资源/*可设置超时,阻塞超过一定时间,超时不在阻塞*/
intsem_timedwait(sem_t*sem,conststructtimespec*abs_timeout);
v操作:释放资源
intsem_post(sem_t*sem);·信号量无属性设置
条件变量设置
初始化和删除函数/*初始化条件变量*/
intpthread_cond_init(pthread_cond_t*restrictcond,constpthread_condattr_t*restrictattr);
intpthread_cond_destroy(pthread_cond_t*cond);//删除条件变量
pthread_cond_tcond=PTHREAD_COND_INITIALIZER;//直接变量初始化(不能赋值)
条件变量发送信号函数
/*唤醒全部因为该条件变量而休眠的线程*/
intpthread_cond_broadcast(pthread_cond_t*cond);/*唤醒其中一个因为该条件变量而休眠的线程*/intpthread_cond_signal(pthread_cond_t*cond);3)等待条件变量信号函数
/*可设置超时,等待超时,则超时返回*/
intpthread_cond_timedwait(pthread_cond_t*restrictcond,pthread_mutex_t*restrictmutex,conststructtimespec*restrictabstime);
/*一直等待,知道到等到唤醒信号*/
intpthread_cond_wait(pthread_cond_t*restrictcond,pthread_mutex_t*restrictmutex);·