线程 --- 嵌入式(Linux)

1、线程的基本概念

线程是进程内的最小执行单元,也被称为轻量级进程(LWP)。一个进程可以包含多个线程,所有线程共享进程的核心资源,同时拥有自己独立的执行上下文(如程序计数器、寄存器、栈)。

2、线程和进程的区别

维度 进程 线程
资源分配 操作系统资源分配的最小单元(独立的地址空间、文件描述符、内存等) 操作系统CPU任务调度的最小单元(不独立分配资源,共享所属进程的资源)
地址空间 每个进程有独立的虚拟地址空间 无独立地址空间,共享进程的文本区、数据区、堆区、文件描述符、信号处理等;仅独享栈区、寄存器上下文、程序计数器 (PC)、线程 ID
独立性 完全独立,一个进程崩溃不影响其他进程 高度依赖进程,一个线程崩溃会导致整个进程终止(进程内所有线程退出)
通信 / 同步 需借助 IPC(管道、消息队列、共享内存等),成本高 直接读写共享变量即可通信,需通过锁 / 信号量等机制解决同步问题
切换开销 大(需切换地址空间、页表等) 小(仅切换执行上下文,无需修改地址空间)

3、线程的创建

  • 调用 pthread_create 创建线程时,系统会为该线程分配独立的栈空间 (Linux 默认栈大小为 8MB,可通过 ulimit -s 查看 / 修改);
  • 线程的文本区(代码)、数据区(全局 / 静态变量)、堆区(动态分配内存)、文件描述符等,均复用所属进程的资源;
  • 线程创建成功后,新线程与主线程并发执行(无固定执行顺序,由 CPU 调度决定)。

4、线程的调度

  • 线程调度规则基本等同于进程调度(支持抢占式调度、时间片轮转、优先级调度等);
  • 宏观上:多个线程 "同时" 执行(并行),因为 CPU 多核或快速切换;
  • 微观上:单核 CPU 中,同一时刻只有一个线程在执行(串行),依赖 CPU 时间片切换实现 "伪并行"。

5、线程的消亡

  • 等同于进程的消亡,线程消亡需要回收线程空间
  • 线程消亡的触发条件:
    1. 线程函数执行完毕(隐式退出);
    2. 调用 pthread_exit 主动退出;
    3. 进程终止(所有线程随之消亡);
    4. pthread_cancel 取消(被动退出)。
  • 线程消亡后必须回收其资源(线程空间):
    • 若未回收,线程会变成 "僵尸线程",占用系统资源(类似僵尸进程);
    • 回收方式:pthread_join(阻塞回收)、pthread_detach(分离线程,系统自动回收)。

6、多线程和多进程优缺点

特性 多进程 多线程
安全性(稳定性) 高:地址空间独立,一个进程崩溃不影响其他进程 低:共享进程资源,一个线程崩溃导致整个进程终止;需处理资源竞争 / 线程安全问题
执行效率 低(切换 / 通信开销大)因为切换进程任务时需要映射不同的物理地址空间,增大系统开销 高(切换 / 通信开销小)因为在同一进程空间内部切换不同的任务
编程复杂度 低(无需处理资源竞争) 高(需处理同步 / 互斥问题)
资源占用 高(每个进程独立占资源) 低(共享进程资源)
适用场景 独立任务、对稳定性要求高(如后台服务、多程序运行) 高并发、数据共享频繁(如网络服务、GUI 程序)
资源竞争 无:地址空间独立,无共享资源竞争 有:共享数据区 / 堆区,需通过互斥锁、条件变量等防止 "竞态条件"
通信难度 高:需 IPC(管道、共享内存等)多进程通信不方便,因为空间独立,没有共享空间 低:直接访问共享变量(全局 / 堆),仅需同步机制(锁 / 信号量)多线程通信非常方便,多线程数据区、堆区共享

7、线程相关函数接口

7.1 pthread_create

  • 函数原型
cpp 复制代码
#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *), void *arg);
  • 功能:创建一个新线程,线程启动后执行start_routine函数;
  • 参数:
    • thread:输出参数,存放新线程的 ID(注意:可用 %#x pthread_self()获取id );
    • attr:线程属性(如栈大小、分离状态),默认属性传NULL
    • start_routine:线程函数入口(函数指针),必须是 void* (*)(void*) 类型(返回值和参数均为 void*);
    • arg:传给线程函数的参数(若传递栈变量地址,需确保变量生命周期长于线程(避免野指针);
  • 返回值:成功返回 0,失败返回错误码 (不是 errno,需用 strerror() 解析,如 perror 不适用);
  • 编译注意:必须链接 pthread 库,编译命令加-lpthread(如gcc test.c -o test -lpthread)。

7.2 pthread_exit

  • 函数原型
cpp 复制代码
void pthread_exit(void *retval);
  • 功能:主动终止当前线程,且不会影响同进程的其他线程;
  • 参数:retval:线程退出的返回值(可被pthread_join()获取),若无需返回值传NULL
  • 注意:主线程调用pthread_exit()仅终止自身,子线程仍会继续执行;若主线程直接return,则整个进程终止。
  • 返回值:缺省

7.3 pthread_join

  • 函数原型
cpp 复制代码
int pthread_join(pthread_t thread, void **retval);
  • 功能:阻塞等待指定线程终止,并回收其资源(避免僵尸线程);
  • 参数:
    • thread:要回收的线程 ID;
    • retval:输出参数,存放线程的返回值(即pthread_exit()retval),无需获取则传NULL
  • 返回值:成功返回 0,失败返回错误码(如线程已分离、线程不存在);
  • 核心作用:
    1. 阻塞回收线程空间资源;
    2. 实现线程同步(主线程等待子线程执行完毕)。
    3. 注意:一个线程只能被一个 pthread_join 回收,重复调用会失败。

示例(创建 + 回收线程):

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>

void *thread_func(void *arg) {
    char *msg = (char *)arg;
    printf("子线程ID:%lu,收到参数:%s\n", (unsigned long)pthread_self(), msg);
    
    // 堆内存,手动分配,主线程回收
    int *ret_val = (int *)malloc(sizeof(int));
    *ret_val = 100;
    pthread_exit((void *)ret_val); // 返回堆地址
}

int main() {
    pthread_t tid;
    char *msg = "Hello Thread";
    int err;

    err = pthread_create(&tid, NULL, thread_func, (void *)msg);
    if (err != 0) {
        printf("创建线程失败:%s\n", strerror(err));
        exit(1);
    }
    printf("主线程:创建的子线程ID为%lu\n", (unsigned long)tid);

    void *ret;
    err = pthread_join(tid, &ret);
    if (err != 0) {
        printf("回收线程失败:%s\n", strerror(err));
        exit(1);
    }
    // 访问堆数据
    printf("主线程:子线程退出,返回值为%d\n", *(int *)ret);
    free(ret); // 必须手动释放堆内存,避免内存泄漏

    return 0;
}
相关推荐
Johny_Zhao4 小时前
OpenClaw中级到高级教程
linux·人工智能·信息安全·kubernetes·云计算·yum源·系统运维·openclaw
Sheffield1 天前
Docker的跨主机服务与其对应的优缺点
linux·网络协议·docker
Sheffield1 天前
Alpine是什么,为什么是Docker首选?
linux·docker·容器
Johny_Zhao2 天前
centos7安装部署openclaw
linux·人工智能·信息安全·云计算·yum源·系统运维·openclaw
haibindev2 天前
在 Windows+WSL2 上部署 OpenClaw AI员工的实践与踩坑
linux·wsl2·openclaw
0xDevNull3 天前
Linux切换JDK版本详细教程
linux
进击的丸子3 天前
虹软人脸服务器版SDK(Linux/ARM Pro)多线程调用及性能优化
linux·数据库·后端
序安InToo4 天前
第6课|注释与代码风格
后端·操作系统·嵌入式
Johny_Zhao5 天前
OpenClaw安装部署教程
linux·人工智能·ai·云计算·系统运维·openclaw