带你搞定多线程(上) —— 线程概念与线程控制

线程概念

理解线程

当操作系统开始运行一个进程的时候,也就意味着操作系统会创建一个pcb对我们的进程进行描述,并且会为该进程创建自己的虚拟地址空间。

如下图:

最右边是我们需要执行的任务,我们可以选择串行处理,就是处理完一个再去处理第二个。但是学习了线程之后我们的进程就可以同时处理下面这三个任务。
在这里插入图片描述
Linux下没有其实没有线程的具体说法,Linux下的线程是通过轻量化进程实现的,所谓轻量化进程就是一个进程中可以存在多个pcb,这些pcb共用一个虚拟地址空间 每一个线程都是进程中的一个执行流,因此多个执行流可以共同工作,于是也就可以并行完成我们上图所示的任务。
在这里插入图片描述
这些所有线程的总和叫做一个线程组,我们也可以将进程理解成就是一个线程组。

  • 进程:是一个程序动态的运行,一个程序运行的描述,cpu资源分配的基本单位
  • 线程:是一个进程中的执行流,执行程序中的某段代码,cpu执行调度的基本单位

线程之间的独有与共享

独有:

  • 线程的标识符:用于区分不同线程
  • 寄存器:执行任务时,cpu轮询切换时,保存当前运行相关信息
  • 栈:防止调用栈混乱
  • 信号屏蔽字:特殊线程执行任务时不希望被某个信号打断
  • erron:全局变量errno可以存放错误原因,当错误发生时,函数的返回值是可以通过非法值来提示错误的发生。
  • 优先级:线程的调度优先级

共享:

  • 虚拟地址空间:代码段,数据段
  • 文件描述符表:线程共用一个文件描述符表,进程中文件都可以操作
  • 信号的回调函数:当我们自定义之后全局生效
  • 用户ID/组ID/工作路径…

之前进程信号的博客说过,信号需要先注销后处理,为了防止被处理多次,这正是防止多线程情况下的时间片轮询所做的。先处理的话,没注销,可能就会被多个线程抢到,从而执行多次。

多线程与多进程的优缺点分析

多线程的优点:

  • 共用一个虚拟地址空间,通信更加灵活方便
  • 创建销毁的成本更低
  • 进程的线程的成本更低

多进程的优点:

  • 健壮性,稳定性更高

多线程的优点正是多进程的缺点,多进程的优点也是多线程的缺点。
多进程和多线程在处理,IO密集型程序/cpu密集型程序的时候都会比单一的进程/线程直接处理要块很多。这也是多进程/多线程的应用场所所在。

CPU密集型程序的执行流个数一般是cpu核心数+1,防止切换调度增加成本

线程控制

线程控制就是对线程的创建》退出》等待》分离进行详细的说明。

前面说过,Linux下实际上是没有线程的概念,线程其实就是轻量化进程,因此下面所说说明的接口是大佬们封装的线程库,线程库提供了一系列操作线程的接口。

线程创建

线程的创建本质上是在内核中创建一个轻量化的进程来实现的。

int pthread_creat(pthread_t *thread,const pthread_attr_t *attr, void*(*start routine)(void*), void *arg);

thread: 输出型参数,获取线程id–线程的操作句柄
attr:线程属性,一般设置成NULL就可以
start routine:函数指针,线程的入口函数
arg:需要传入线程入口函数的参数

成功返回0,失败返回错误编号。

注意:
上面函数的thread参数其实是一个空间的首地址,叫做tid当线程被创建后,独有的数据就会被描述在共享区,而这个共享区的首地址就是线程的操作句柄,用于操作这个线程。
在这里插入图片描述
运行结果:
在这里插入图片描述

每个线程都有自己的pid,但是线程创建成功后,通过ps命令仍然只能看见一个pid而这个pid其实叫做tgid,是线程组id,等于主线程id。

只能看到主线程pid
在这里插入图片描述

通过ps -efL就可以看到所有线程的pid了(LWP列)。
可以看到有两个pthread_creat.
在这里插入图片描述

线程终止

线程的终止就是线程的退出,线程可以异常退出也可以我们自己手动退出,下面我们讲解如何让一个线程退出(正常退出)

void pthread_exit(void* revtal);

作用:退出调用该接口的线程
revtal:保存退出返回值

int pthread_cancel(pthread_t thread);

作用:传入某个线程的操作句柄,从而使该线程被动取消。
参数:需要退出线程的tid

注意:

上面两个函数都是退出线程的,即使退出主线程,其余线程也会继续工作,直到所有线程都退出,但是exit与main中的return 退出的是整个进程。

代码:
在这里插入图片描述

执行结果:
在这里插入图片描述
可以看到主线程退出后,剩余线程仍然正常工作。

线程等待

线程等待:等待一个线程的退出,获取线程的返回值,并且回收线程所占的资源。
默认情况下一个线程创建出来是需要被等待的,否则就会造成资源的泄露

int pthread_join(pthread_t thread, void **revtal)

thread:等待的指定线程tid
revtal:输出型参数,获取线程返回值

线程分离

线程创建出来默认是需要等待的,但是我们有时候不关心一个线程的返回值,也可以通过设置,让一个线程不用被等待,这就叫做线程的分离。

我们通过将线程的joinable属性修改为detach属性就是线程分离。
属性为detach的线程退出的时候会自己释放资源。

int pthread_detach(pthread_t thread);

当然一个线程也可以自己将自己设置成detach属性,我们通过pthread_self获得自己的tid

int pthread_self(void);

返回值就是自己的tid.

猜你喜欢

转载自blog.csdn.net/ifwecande/article/details/107568892
今日推荐