【Linux】初识线程

avatar
作者
筋斗云
阅读量:0

目录

什么是线程

线程的优点 

线程的缺点

线程异常 

线程接口

创建线程

线程等待

线程终止或者取消

获取当前线程id

分离线程


什么是线程

        在一个程序里的一个执行路线就叫做线程,更准确的定义是:线程是“一个进程内部的控制序列”。

  • 一切进程至少都有一个执行线程。
  • 线程在进程内部运行,本质是在进程地址空间运行。
  • 在Linux系统中,在CPU视角中,看到的PCB都要比传统的进程更加轻量化。

线程的优点 

  • 创建一个新线程的代价要比创建一个新进程小得多
  • 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
  • 线程占用的资源要比进程少很多
  • 能充分利用多处理器的可并行数量
  • 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
  • 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
  • I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。

线程的缺点

1.性能损失

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

2.健壮性降低 

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

3.缺乏访问控制

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

4.编程难度提高

 编写与调试一个多线程程序比单线程程序困难得多

线程异常 

  • 单个线程如果出现除零,野指针问题导致线程崩溃,进程也会随着崩溃
  • 线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出

线程接口

        头文件#include <phread.h>,这个库属于第三方库,也是原生线程库,linux中编写多线程代码都需要使用这个库。

        操作系统内部没有线程的概念,只有轻量级进程,因此我们创建线程需要使用pthread线程库。phtread线程库对操作系统创建轻量级进程接口进行封装,为用户提供直接创建线程的接口。

轻量级进程接口 clone(回调函数,独立栈)

综上所述,线程的概念是库给我们维护的, 这个原生线程库是动态库,因此需要加载到内存中,给每个线程分配一个独立栈的内存空间。

查看所有线程 

ps -aL

通过LWP(light weight process)区分不同的执行流 。PID等于LWP,就表明该线程是主线程,不相等的话,就代表该线程是被创建出来的。

创建线程

int pthread_create(pthread_t *thread,

                                const pthread_attr_t *attr,

                                void *(*start_routine) (void *),

                                void *arg);

成功返回0,失败返回错误码

  • pthread_t *thread:输出型参数,thread id。
  • const pthread_attr_t *attr:线程属性,一般不管,设置为nullptr。
  • void *(*start_routine) (void *):返回值是void* ,参数是void* 的函数指针,作用是传入要该线程执行的函数方法。

        void 不能定义变量,因为他无法确定大小,但是void* 可以,用void* 可以接收任意类型的。

  •  void *arg:创建线程成功,新线程回调线程函数的时候,需要参数,这个参数就是给线程函数传递的,也就是第三个函数指针所需要的参数。

当一个函数被多个执行流同时执行,则称该函数被重入了

线程等待

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

  • pthread_t thread:要等待的线程id。 
  • void **retval:接收所等待线程的返回值。

线程终止或者取消

其中exit是用来终止进程的,不能用来终止线程。

终止线程除了return以外,还有一个pthread_exit((void*)100),这里所说的终止线程,是在线程执行的方法函数中。

除了这两种方法以外,还可以在主线程中通过pthread_cancel(tid)取消线程

获取当前线程id

pthread_t pthread_self(void);

返回值为当前线程id

每个线程的库(phtread库)级别的tcb的起始地址叫做线程的tid

定义一个每个线程私有的全局变量

__thread int g_val = 100;

__thread只能定义内置类型,不能用来修饰自定义类型

分离线程

        默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。

        如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。

int pthread_detach(pthread_t thread);

也可以是线程组内 其他线程对目标线程进行分离,也可以是线程自己分离

pthread_detach(pthread_self());

 joinable和分离是冲突的,一个线程不能既是joinable又是分离的。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!