嵌入式学习 day33:线程进阶

一、线程分离属性

1.1 什么是分离属性

之前学的线程需要用 pthread_join() 回收,否则会变成僵尸线程。如果不需要等待线程的返回值,可以把它设为分离状态: 线程结束后系统自动回收资源,不用手动 join

属性 特点
加入(默认) 需要 pthread_join() 回收
分离 线程结束自动回收,无需 join

1.2 设置分离属性

c

复制代码
pthread_attr_t attr;
pthread_attr_init(&attr);                      // 初始化属性
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);  // 设为分离
pthread_create(&tid, &attr, thread_func, NULL); // 创建分离线程
pthread_attr_destroy(&attr);                   // 销毁属性

c

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

void *thread_func(void *arg)
{
    printf("分离线程执行中\n");
    sleep(1);
    return NULL;
}

int main(void)
{
    pthread_t tid;
    pthread_attr_t attr;
    
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&tid, &attr, thread_func, NULL);
    pthread_attr_destroy(&attr);
    
    // 不需要 pthread_join,线程结束后自动回收
    sleep(2);
    return 0;
}

二、多进程 vs 多线程

对比项 多进程 多线程
运行效率 低(创建开销大) 高(共享进程空间)
安全性 高(进程独立,一个崩溃不影响其他) 低(线程崩溃导致整个进程结束)
通信方式 复杂(需要IPC) 方便(共享全局变量)
通信复杂度 低(但需要处理同步)

三、线程间通信与资源竞争

3.1 线程间通信方式

线程之间通过共享全局变量 来通信,比进程间通信简单得多。但多个线程同时修改同一个全局变量时,会出现资源竞争

c

复制代码
int money = 100;

void *withdraw(void *arg)
{
    if (money >= 50) {
        usleep(100);   // 模拟时间片切换
        money -= 50;
    }
}

两个线程同时取钱,可能都通过判断,导致最终结果错误。

四、互斥锁

4.1 基本概念

互斥锁(Mutex)让多个线程排着队访问共享资源,谁先拿到锁谁先操作,操作完解锁,其他人才能继续。

4.2 函数接口

c

复制代码
#include <pthread.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  // 静态初始化
// 或
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);    // 加锁(阻塞)
int pthread_mutex_unlock(pthread_mutex_t *mutex);  // 解锁

4.3 使用示例

c

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

int money = 100;
pthread_mutex_t mutex;

void *withdraw(void *arg)
{
    pthread_mutex_lock(&mutex);    // 加锁
    if (money >= 50) {
        usleep(100);
        money -= 50;
        printf("取钱成功,余额:%d\n", money);
    } else {
        printf("余额不足\n");
    }
    pthread_mutex_unlock(&mutex);  // 解锁
    return NULL;
}

int main(void)
{
    pthread_t t1, t2;
    pthread_mutex_init(&mutex, NULL);
    pthread_create(&t1, NULL, withdraw, NULL);
    pthread_create(&t2, NULL, withdraw, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_mutex_destroy(&mutex);
    return 0;
}

4.4 死锁

两个线程各自拿着一把锁,同时等对方释放,谁都动不了,程序卡死。

避免死锁的方法

  1. 使用 pthread_mutex_trylock() 替代 pthread_mutex_lock()(不阻塞,拿不到锁就返回)

  2. 多把锁时保持一致的加锁顺序

五、信号量

5.1 什么是信号量

信号量是一种资源计数器,用来控制同时访问共享资源的线程数量。比如限制最多3个线程同时访问某资源。

5.2 函数接口

c

复制代码
#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t *sem);
int sem_wait(sem_t *sem);     // 申请资源(P操作),资源数>0则减1,=0则阻塞
int sem_post(sem_t *sem);     // 释放资源(V操作),资源数+1
  • pshared:0 表示线程间共享,非0 表示进程间共享

  • value:初始资源数量

5.3 互斥锁 vs 信号量

互斥锁 信号量
本质 锁(只能一个线程持有) 计数器(可多个线程同时访问)
操作 lock / unlock wait / post
适用场景 保护临界区 控制并发数量

六、今日总结

今天学了线程同步的核心内容:

线程分离

  • pthread_attr_setdetachstate() 设置分离属性

  • 分离线程结束自动回收,无需 join

互斥锁

  • pthread_mutex_lock() 加锁,pthread_mutex_unlock() 解锁

  • 保护临界区,防止资源竞争

  • 死锁:多锁加锁顺序不一致导致

信号量

  • sem_wait() 申请资源,sem_post() 释放资源

  • 控制同时访问的线程数量

今日感悟

线程共享数据方便,但是绕不开资源竞争的问题。互斥锁让多个线程排着队访问共享资源,虽然牺牲了一点性能,但换来了数据安全。信号量更灵活,能控制同时访问的线程个数,适合限流场景。多进程安全但慢,多线程快但不安全;锁能保护数据但可能死锁。没有完美的方案,只有适合场景的选择。

相关推荐
牢姐与蒯17 分钟前
Linux进程(四).进程优先级以及进程切换,进程调度
linux·运维·服务器·ubuntu
大爱编程♡27 分钟前
Linux C 语言文件 IO 与构建工具实战指南
linux·服务器
MartinYeung51 小时前
[论文学习]AI-Trader:实时金融市场中自主代理的基准测试
人工智能·深度学习·学习
懿路向前1 小时前
【HarmonyOS学习笔记】2026-08-27 | 端插件踩坑与设计取舍
笔记·学习·harmonyos
QuZhengRong1 小时前
【AI】Agent 全栈进阶|Agent 设计模式
人工智能·学习·设计模式·llm·agent
SuperByteMaster1 小时前
ARM Architecture Procedure Call Standard(ARM架构过程调用标准)
c语言
Linux运维技术栈1 小时前
深度拆解 Linux logrotate 重复切割问题:根因、排查与生产级根治方案
linux·logrotate
ouynagda1 小时前
Linux多线程:互斥锁与信号量学习笔记
linux·笔记·学习
重生之我是Java开发战士2 小时前
【Java EE】认识Linux与项目部署
java·linux·java-ee