Linux线程基础

线程概述:

在 Linux 系统中,线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程可以拥有多个线程,这些线程共享该进程的资源(如内存空间、文件描述符等),这种共享减少了资源的复制,提高了效率。但每个线程都拥有自己独立的栈空间、寄存器和程序计数器,这使得它们能够并发执行不同的代码段

进程与线程的联系与区别:

联系:

一个进程可以被理解为由进程资源、一个主线程以及若干子线程组成的集合

  1. 并发执行:进程和线程都能实现并发执行,允许多个任务同时进行。
  2. 资源管理:进程和线程都需要操作系统进行资源管理,如内存、文件描述符等。
  3. 执行程序:进程和线程都是用来执行程序的,它们都需要程序代码和数据

区别:

  1. 资源拥有

    • 进程:拥有独立的内存空间,每个进程都有自己独立的地址空间。
    • 线程:线程是进程的一部分,多个线程共享同一个进程的内存空间和资源。
  2. 创建开销

    • 进程:创建一个新进程需要进行大量的资源分配和初始化,开销较大。
    • 线程:线程的创建和销毁开销相对较小,因为它们共享进程的资源
  3. 独立性

    • 进程:进程是独立的执行环境,一个进程崩溃不会直接影响到其他进程。
    • 线程:线程之间存在较高的耦合度,一个线程的崩溃可能会影响到同进程的其他线程。
  4. 调度

    • 进程:进程是操作系统进行资源分配和调度的基本单位。
    • 线程:线程是CPU调度和执行的基本单位,线程的调度由操作系统的线程调度器负责

Linux下查看线程的相关命令:

1.pidstatsysstat 工具包中的一个命令,它可以报告或接收有关各个进程和线程的统计信息

安装:在 Ubuntu 系统上,可以通过以下命令安装 sysstat 工具包

sudo apt install sysstat

选项

  • -t:显示指定进程所关联的线程。
  • -p:指定进程 ID

 使用pidstat 命令可以用来查看特定进程及其线程的信息。

pidstat -t -p pid

 2.top 命令提供了一个实时的进程监控界面。

选项

  • -H:显示线程。
  • -p:指定要监视的进程 ID
top -H -p pid

3.ps 命令用于显示当前运行的进程信息。

选项

  • -T:显示线程
ps -T

这将显示系统中所有线程的列表。结合其他选项,如 -p 可以指定特定的进程 ID

ps 命令结合 aux 选项,可以显示所有进程及其线程:

ps aux | grep <process_name>

 线程资源:

  • 共享资源

  • 线程共享进程的以下资源:
    • 同一块地址空间。
    • 文件描述符表。
    • 信号的处理方式(如:SIG_DFLSIG_IGN 或者自定义的信号处理函数)。
    • 当前工作目录。
    • 用户 ID 和组 ID。
  • 独立资源

  • 线程拥有以下独立的资源:
    • 线程栈:每个线程都有自己的栈空间,用于存储局部变量和函数调用的上下文。
    • 线程 ID:每个线程都有一个唯一的标识符。
    • 寄存器的值:每个线程有自己的寄存器集合,用于存储状态信息。
    • errno 变量:每个线程有自己的 errno 值,用于错误处理。
    • 信号屏蔽字以及调度优先级:线程可以有自己的信号屏蔽字和调度优先级

线程的基础操作:

1.创建线程

函数描述:

pthread_create()函数在调用进程中启动一个新线程。新线程通过调用start_routine()开始执行;arg作为start_routine()的唯一参数传递

函数头文件:
#include <pthread.h>

函数原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

函数参数:
thread:一个指向 pthread_t 变量的指针,该变量将被设置为新创建线程的线程标识符。
attr:指向 pthread_attr_t 结构的指针,该结构定义了新线程的属性。如果传递 NULL,则使用默认的线程属性。
start_routine:新线程启动时将调用的函数。这个函数必须有以下的函数原型:
void* function_name(void* arg);
它接受一个 void* 类型的参数,并返回一个 void* 类型的值。
arg:传递给 start_routine 函数的参数

函数返回值:
成功:返回 0。
失败:返回错误码
EAGAIN 表示资源不足,无法创建新线程
EINVAL 属性中的无效设置
EPERM 没有权限设置调度策略和attr中的参数

 2.分离线程

线程类型:

线程可以被分为两种类型:可结合的(joinable)和可分离的(detached)。

可结合的线程(Joinable Threads)
  • 当使用 pthread_create 创建线程时,新线程默认是可结合的(也称为可连接的)。
  • 可结合的线程在结束时不会自动释放其资源,而是保持状态,等待其他线程(通常是创建它的线程)调用 pthread_join 来回收其资源。
  • 调用 pthread_join 的线程可以获取结束线程的返回值。
  • 如果可结合的线程结束时没有其他线程调用 pthread_join,则它将成为一个僵尸线程,占用系统资源而不被释放。
可分离的线程(Detached Threads)
  • 可分离的线程是结束时自动释放其资源,无需其他线程调用 pthread_join
  • 可以通过调用 pthread_detach 将一个可结合的线程转换为可分离的线程。
  • 可分离的线程一旦结束,其资源立即被操作系统回收,且它们的返回值不会被保存。
  • 可分离的线程不能被加入(joined),尝试对它们调用 pthread_join 将失败

函数描述:

pthread_detach() 函数用于将一个线程标记为分离线程(detached thread)。分离线程在结束时不会留下任何资源需要其他线程去回收,它的资源将由操作系统自动回收,也不需要其他线程调用 pthread_join() 来回收它的资源。如果尝试对一个已经分离的线程调用 pthread_join(),将会导致错误。

函数头文件:
#include <pthread.h>

函数原型:
int pthread_detach(pthread_t thread);

函数参数:
thread:要分离的线程的线程标识符

函数返回值:
成功:返回 0。
失败:返回错误码。
EINVAL 线程不是可结合的线程
ESRCH 找不到具有该ID的线程

 3.线程等待

函数描述:

pthread_join() 函数阻塞调用它的线程,直到指定的线程结束。一旦被等待的线程结束,pthread_join() 将该线程的返回值存储在 retval 指向的位置。如果不需要线程的返回值,可以将 retval 设置为 NULL

只能对可结合的(joinable)线程调用 pthread_join()。如果线程已经被分离(detached),则调用 pthread_join() 将失败。

一旦对线程调用了 pthread_join(),该线程的线程标识符将变得无效。

函数头文件:
#include <pthread.h>

函数原型:
int pthread_join(pthread_t thread, void **retval);

函数参数:
thread:要等待的线程的线程标识符。
retval:一个指向 void* 类型的指针的指针,用于存储结束线程的返回值

函数返回值:
成功:返回 0。
失败:返回错误码。
EDEADLK 检测到死锁(例如,两个线程试图相互连接);或thread指定调用线程。
EINVAL  线程不是一个可接合的线程。
EINVAL  另一个线程已处于等待与该线程合并的状态
ESRCH   找不到ID为thread的线程。

4.线程退出 

函数描述:

pthread_exit() 函数终止调用它的线程。如果其他线程使用 pthread_join() 等待这个线程结束,它们可以获取 retval 参数指定的返回值。如果线程是分离的(detached),则其资源将自动被操作系统回收。

函数头文件:
#include <pthread.h>

函数原型:
void pthread_exit(void *retval);

函数参数:
retval:一个 void* 类型的指针,用作线程的返回值。这个返回值可以被其他线程通过 pthread_join() 函数获取

函数返回值:
此函数不返回给调用者

结语:

无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值