快捷搜索:  汽车  科技

linux中的进程与线程(详解Linux线程概念创建线程)

linux中的进程与线程(详解Linux线程概念创建线程)(3)线程的优点3>线程共享进程的数据,但也拥有自己的一部分数据(如:线程ID、一组寄存器、栈、errno、信号屏蔽字、调度优先级、上下文关系)。(1)区别与联系1>进程是承担系统资源分配的基本单位;2>线程是程序执行的最小单位(承担资源调度的基本单位);

概述

线程是程序中完成一个独立任务的完整执行序列,即一个可调度的实体;进程相当于运行中程序的一种抽象。根据运行环境的调度者的身份,线程可分为内核线程和用户线程。内核线程,在有的系统上称为LWP(Light Weight Process,轻量级线程),运行在内核空间,由内核调度;用户线程运行在用户空间,由线程库来调度。当进程的一个内核线程获得CPU的使用权时,它就加载并运行一个用户线程。可见,内核线程相当于用户线程运行的‘容器’,一个进程可以拥有M个内核线程和N个用户线程,其中M<=N,并且一个系统的所有进程中,M和N的比值是固定的。


线程的概念

1.什么是线程

在一个程序里的一个执行路线叫做线程(准确来说,线程是一个进程内部的控制序列),一切进程都至少有一个执行线程。

2.进程和线程

(1)区别与联系

1>进程是承担系统资源分配的基本单位;

2>线程是程序执行的最小单位(承担资源调度的基本单位);

3>线程共享进程的数据,但也拥有自己的一部分数据(如:线程ID、一组寄存器、栈、errno、信号屏蔽字、调度优先级、上下文关系)。

(3)线程的优点

1>创建一个新线程的代价要比创建一个新进程小得多

2>与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多

3>线程占用的资源比进程少很多

4>能充分利用多处理器的可并行数量

5>在等待慢速I/O操作结束的同时,程序可执行其他的计算任务

6>计算密集型应用,为了能在多处理器系统上运行,将将计算分解到多线程中实现

7>I/O密集型应用,为了提高性能,将I/O操作重叠(线程可以等待不同的I/O操作)

(4)线程的缺点

1>性能损失(一个很少被外部事件阻塞的计算密集型线程往往无法与其他线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变)

2>健壮性降低(编写多线程需要更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量二造成不良影响的可能性是很大的,换句话说,线程之间是缺乏保护的)

3>缺乏访问控制(进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响)

4>编程难度提高(编写与调试一个多线程比单线程程序困难得多)


线程控制

POSIX线程库

1>与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的

2>要使用这些库函数,要通过引入头文件

3>链接这些线程函数库时要使用编译器命令的“-lpthread”选项

1.创建线程

int pthread_create(pthread_t *thread const pthread_attr_t *attr void *(*start_routine)(void*) void *arg);

参数说明:

thread:返回线程ID attr:设置线程的属性,attr为NULL表示使用默认属性 start_routine:是一个函数地址,线程启动后要执行的函数 arg:传给线程启动函数的参数

返回值:成功返回0;失败返回错误码

linux中的进程与线程(详解Linux线程概念创建线程)(1)

2.进程ID和线程ID

(1)在Linux中,目前的线程实现是NPTL(Native POSIX Thread Libaray)。在这种实现下,线程又被称为轻量级进程(Light Weighted Process),每一个用户态的线程,在内核中都对应一个调度实体,也拥有自己的进程描述符(task_struct结构体)

(2)在没有线程之前,一个进程对应内核里的一个进程描述符,对应一个进程ID。但是引入线程概念之后,情况发生了变化,一个用户进程下管辖N个用户态线程,每个线程作为一个独立的调度实体在内核态都有自己的进程描述符,进程和内核描述符一下子就变成了1:N的关系,POSIX标准又要求进程内的所有线程调用getpid函数时返回相同的进程ID。

linux中的进程与线程(详解Linux线程概念创建线程)(2)

ps命令中的-L选项,会显示如下信息

LWP:线程ID,即gettid()系统调用的返回值。

NLWP:线程组内线程的个数

可以看出:上面的admin.log进程是单线程的,进程组ID为15969,线程ID为15969(也可以多线程)

(3)Linux提供了gettid系统调用来返回其线程ID,可是glibc并没有将该系统调用封装起来,在开放接口来供程序员使用。如果确实需要获得线程ID,可以采用如下方法:

#include<sys/syscall.h> pid_t tid; tid = syscall(SYS_gettid);

linux中的进程与线程(详解Linux线程概念创建线程)(3)

3.线程ID及进程地址空间布局

(1)pthread_create函数会产生一个线程ID,存放在第一个参数指向的地址中,该线程ID和前面说的线程ID不是一回事。(之前说的线程ID属于进程的调度范畴,因为线程是轻量级进程,是操作系统调度器的最小单位;而这里的说的线程ID属于NPTL线程库的范畴)。

(2)线程库NPTL提供了pthread_self函数,可以获得线程自身的ID:

pthread_t pthread_self(void);

(3)注意:pthread_t 的类型取决于实现(对于Linux目前实现的NPTL实现而言,pthread_t 类型的线程ID,本质上就是一个进程地址空间上的一个地址)

linux中的进程与线程(详解Linux线程概念创建线程)(4)

4.线程终止

(1)如果只需要终止某个线程而不是整个进程,有以下三种操作:

1>从线程函数return。(该方法对于主线程不适用,从main函数return相当于调用exit);

2>线程可以调用pthread_exit函数来终止自己;

3>一个线程可以调用pthread_cancel终止同一进程中的另外一个线程。

(2)pthread_exit函数(线程终止)

void pthread_exit(void *value_ptr);

注意:pthread_ptr不能指向一个局部变量;该函数没有返回值

(3)pthread_cancel函数(取消一个执行中的线程)

int pthread_cancel(pthread_t thread);

注意:thread为线程ID;该函数调用成功返回0,失败返回错误码


后面小编会分享更多Linux方面的干货,感兴趣的朋友可以关注一下~

linux中的进程与线程(详解Linux线程概念创建线程)(5)

猜您喜欢: