详解线程、了解进程与线程的区别以及线程分离与结合属性

来源:互联网 发布:微博没有mac版 编辑:程序博客网 时间:2024/05/20 01:08

一、什么是线程?

我们知道,进程在各自独立的地址空间中运行,进程之间共享数据需要用mmap或者进程间通信机制,但是有些情况需要在一个进程中同时执 行多个控制流程,这时候线程就派上了用场。

实际上,在Linux下没有真正意义上的线程,它是由进程模拟出来的。

进程是承担分配系统资源的基本实体,线程是操作系统或进程调度的最小单位,线程是进程的执行分支,线程是在进程内部(地址空间)执行的。

由于同一进程的多个线程共享同一地址空间,因此代码和数据都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一 个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:

(1)文件描述符
(2)信号处理方式
(3)当前工作目录
(4)用户id和组id

但是以下资源就是线程独享的:

(1)线程id
(2)上下文,包括各种寄存器的值、程序计数器和栈指针
(3)栈空间
(4)errno变量
(5)信号屏蔽字
(6)调度优先级

线程的最主要的特点:

(1)线程在运行时,会产生临时变量,由于临时变量是在栈上保存的。所以每个线程都有自己的私有栈结构。

(2)每个线程都有自己的上下文信息

二、进程与线程的区别

(1)进程是独立的,每创建一个进程时,都要有它自己的pcb,地址空间,页表和物理内存。但是创建线程时就不必这么繁琐,只需创建自己的pcb即可。

(2) 进程是承担分配系统资源的基本实体,线程是操作系统或进程调度的最小单位。

(3)进程有独立的地址空间,一个进程崩溃后,不会对别的进程产生影响。而线程之间没有单独的地址空间,一个线程挂掉就等于整个进程挂掉。

三、线程的控制代码

线程库函数是由POSIX标准定义的,称为POSIX thread或者pthread。在Linux上线程函数位于libpthread共享库中,因此在编译时要加上-lpthread选项。为了方便我们在Makefile中加入此选项,如下图:

这里写图片描述

(1).创建线程
创建线程时我们使用的是pthread_create函数
函数原型为:

这里写图片描述

创建线程id时要用的是pthread_self函数
函数原型为:

     pthread_t pthread_self(void);

了解了以上知识,让我们来看看创建线程的具体代码:

这里写图片描述

代码运行成功后的结果为:

这里写图片描述

(2).等待线程
等待线程用的函数为 pthread_join,函数原型为:

int pthread_join(pthread_t thread, void **retval);

void **retval指的是获得新线程的退出结果。pthread_join是采用以阻塞方式等待

它的作用是:
a.保证退出时的退出顺序
b.回收新线程退出时的资源情况
c.获得新线程退出时结果是否正确的退出返回值

接下来我们来看看相关等待线程函数的相关代码

这里写图片描述

代码运行成功后的结果为4s后输出以下信息:

这里写图片描述

(3).终止线程

终止线程有3种方式:
a:从线程函数内部return。注意:主线程退出,所有线程都会退出
b:使用pthread_exit函数终止线程。函数原型为:

      void pthread_exit(void *retval);

具体代码如下:
这里写图片描述

代码运行成功的结果为:4s后线程终止,主线程join成功。输出以下结果:

这里写图片描述

c:使用pthread_cancel函数取消线程,函数原型为

    int pthread_cancel(pthread_t thread);

具体代码如下:

这里写图片描述
代码运行成功后的结果为:1s后输出以下信息:

这里写图片描述

这个时候的返回值是-1的原因是:如果thread线程被别的线程调.用pthread_cancel异常终掉,value_ptr所指向的单元.里存放
的是常数PTHREAD_CANCELED。在Linux的pthread库中常数PTHREAD_CANCELED的值是-1。

四、线程分离与结合属性

a:线程是可结合的或者是分离的。

b:线程不管怎么分离,都会在进程内部执行

c:一个可结合的线程能够被其他线程收回其资源和杀死。在被其他线程回收之前,它的存储器资源是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。

d:默认情况下,线程被创建成可结合的。为了避免存储器泄漏,每个可结合线程都应该要么被显示地回收,即调用pthread_join;要么通过调用pthread_detach函数被分离。

e:如果一个可结合线程结束运行但没有被join,则它的状态类似于进程中的僵尸进程即还有一部分资源没有被回收,所以创建线程者应该调⽤用pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源。

f:由于调用pthread_join后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。

例如,在Web服务器中当主线程为每个新来的连接请求创建一个子线程进
行处理的时候,主线程并不希望因为调用pthread_join而阻塞(因为还要继续处理之后到来的连接请求)

这时可以在子线程中加入代码pthread_detach(pthread_self())或者父线程pthread_detach(thread_id)(非阻塞,可立即返回)
这将该子线程的状态设置为分离的(detached),如此一来,该线程运行结束后会自动释放所有资源。

原创粉丝点击