一, 线程的概念
<1> 线程,又是被称为轻量级进程(Lightweight Process LWP),是操作系统或进程调度的最小单位。是在进程内部(地址空间)执行的。每一个程序都至少有一个线程,若程序只有一个线程,那么就是程序本身。
实际上,在Linux下没有真正意义上的线程,它是由进程模拟出来的。
由于同一进程的多个线程共享同一地址空间,因此代码和数据都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一 个全局变量,在各线程中都可以访问到,除此之外,各线程共享以下进程资源和环境:
(1)文件描述符
(2)信号处理方式
(3)当前工作目录
(4)用户id和组id
但是以下资源就是线程独享的:
(1)线程id
(2)上下文,包括各种寄存器的值、程序计数器和栈指针
(3)栈空间
(4)errno变量
(5)信号屏蔽字
(6)调度优先级
<2> 线程的优点:
1.创建一个新线程的代价要比创建一个新进程小得多(因此有时thread被称为轻型进程)
2.与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多(提高了并发程度)
3.线程占用的资源要比进程少很多
二, 进程与线程的区别
1.计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。
2.假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。背后的含义就是,单个CPU一次只能运行一个任务。
3.进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。
4.一个车间里,可以有很多工人。他们协同完成一个任务。线程就好比车间里的工人。一个进程可以包括多个线程。
5.车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。
6.每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。
7.还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。
区别:
进程——资源分配的最小单位,线程——程序执行的最小单位
进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)。
三, 线程的创建/等待/终止
我们将要学习的线程库函数是由POSIX标准定义的,称为POSIX thread或者pthread。在Linux 上线程函数位于libpthread共享库中,因此在编译时要加上-lpthread选项。
<1>. 线程的创建
<2>. 线程的等待
它的作用是:
a.保证退出时的退出顺序
b.回收新线程退出时的资源情况
c.获得新线程退出时结果是否正确的退出返回值
结果如下:
<3>.线程的终止
终止方式有3种
1.从线程函数内部return。注意:主线程退出,所有线程都会退出。
2. 一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
3.使用pthread_exit函数终止线程。
<4>.线程的取消
测试代码:
结果如下:
这个时候的返回值是-1的原因是:如果thread线程被别的线程调用pthread_cancel异常终掉,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED。在Linux的pthread库中常数PTHREAD_CANCELED的值是-1。
四, 线程的分离与结合属性
线程属性标识符:pthread_attr_t 包含在 pthread.h 头文件中。
typedef struct
{
int etachstate; //线程的分离状态
int schedpolicy; //线程调度策略
structsched_param schedparam; //线程的调度参数
int inheritsched; //线程的继承性
int scope; //线程的作用域
size_t guardsize; //线程栈末尾的警戒缓冲区大小
int stackaddr_set; //线程的栈设置
void* stackaddr; //线程栈的位置
size_t stacksize; //线程栈的大小
}pthread_attr_t;
在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。
为了避免存储器泄漏,每个可结合线程都应该要 么被显示地回收,即调用pthread_join;要么通过调用pthread_detach函数被分离。
由于调用pthread_join后,如果该线程没有运行结束,调用者会被阻塞。因此,我们就可以在子线程中加入pthread_detach(pthread_self())或者父线程调用pthread_detach(thread_id)(非阻塞,可立即返回) 。
这样将子线程的状态设置为分离的(detached),如此一来,该线程运行结束后会自动释放所有资源。