Linux软件编程(6)线程间通信

前两天学习了进程和线程的相关内容,今天来学习线程间的通信。

多线程程序是指多个线程跑在同一个进程里面,所有线程共享进程的全局变量、堆、文件描述符。按理来说,线程之间直接读写全局变量就能交换数据,看着很方便,但这里藏着很大的问题。

一、为什么不能随便直接用全局变量通信

多个线程同时读写同一个全局变量,就会产生资源竞争。

举个简单例子,一个变量count,线程A做count++,线程B也做count++。

count++并不是CPU一条指令直接完成,它分为:读变量、自增、写回内存三步。

如果两个线程刚好在中间互相打断,最后算出来的结果就会出错,这就是竞态问题。

原子操作:不能被CPU任务调度打断的最小操作,一步执行完,中途不会切走别的线程。我们的普通i++不是原子操作。

临界区:加锁和解锁中间包裹的那一段代码。这一块代码,同一时间只允许一个线程进去执行,别的线程要排队等待。

想要安全访问共享资源,就需要互斥锁。

二、互斥锁 pthread_mutex

互斥锁,作用就是保护临界区。谁拿到锁,谁才能执行临界区代码;没拿到锁的线程阻塞等待。

四个核心函数

  1. pthread_mutex_init

    初始化互斥锁。

    参数:锁的地址,第二个attr填NULL使用默认属性。

    返回0代表成功,失败返回非0。

  2. pthread_mutex_destroy

    销毁互斥锁。程序结束前要销毁,释放锁占用的资源。

  3. pthread_mutex_lock

    上锁。如果锁已经被别人拿走,当前线程就阻塞在这里,一直等到锁被释放。

  4. pthread_mutex_unlock

    解锁。用完共享资源一定要解锁,不然别的线程会一直卡死等待。

使用简单流程

pthread_mutex_init 初始化锁

线程内:

pthread_mutex_lock();

// 临界区,操作共享全局变量

pthread_mutex_unlock();

pthread_mutex_destroy(); // 最后销毁

注意:lock和unlock必须成对。中途return、break跳过unlock,就会死锁。

三、死锁

死锁:多个线程互相拿着对方需要的锁,谁都不肯释放,所有线程全部卡住不动,程序彻底僵住。

死锁四个必要条件

  1. 互斥条件:资源同一时刻只能一个线程使用

  2. 不可剥夺条件:已经拿到的锁,不能被别的线程强行抢走

  3. 请求保持:线程已经拿着锁,又去申请别的锁,原有锁不释放

  4. 循环等待:线程A拿锁1等锁2;线程B拿锁2等锁1,形成循环

四个条件全部满足,就会发生死锁。破坏任意一个,就可以避免死锁。

如何避免死锁?

  1. 使用pthread_mutex_trylock,尝试拿锁,拿不到不会阻塞,可以直接返回,避免卡死。

  2. 多把锁的时候,所有线程加锁顺序保持一致。大家都先拿锁A,再拿锁B,就不会出现循环等待。

四、信号量 sem

信号量可以把资源看成一个计数器,不仅仅能做互斥,还可以做线程同步。

资源是有限的,信号量就用来记录可用资源数量,支持初始化、销毁、申请、释放。

四个核心函数

  1. sem_init:初始化信号量
    int sem_init(sem_t *sem, int pshared, unsigned int value);
    • sem:信号量变量地址

• pshared:0代表同一个进程内部线程共享;非0代表进程之间共享

• value:信号量初始值

  1. sem_destroy:销毁信号量,释放资源

  2. sem_wait:申请资源(P操作)

    资源计数大于0,计数减一,直接往下执行;

    资源等于0,线程阻塞等待,直到有资源释放出来。

  3. sem_post:释放资源(V操作)

    信号量计数+1,唤醒正在等待这个信号量的线程。

    小区别:

    互斥锁:同一时间只能一个线程进入临界区。

    信号量:初始值可以设置大于1,可以允许多个线程同时获取资源。

    五、总结

  4. 互斥锁(mutex):主要用于互斥访问,保护临界区,锁只有两种状态:上锁、解锁。

  5. 信号量(sem):既可以实现互斥,更擅长做同步,控制线程执行先后顺序,自带计数器。

    互斥锁、信号量,只解决同一个进程内部线程之间通信。

    进程之间通信,要用管道、FIFO、消息队列这些,进程之间虚拟地址互相隔离,全局变量不能直接互通。

相关推荐
Rain的Java大神之路21 分钟前
PC版网站被狂刷怎么处理
java·数据库·redis·后端·mysql·web安全·运维开发
闻哥30 分钟前
小表驱动大表——SQL查询优化的核心原则(深度剖析+流程图)
数据库·sql·流程图
whcyhhh35 分钟前
头歌实践教学平台:数据科学与大数据技术导论(十六)
大数据·开发语言·python
萌动的小火苗35 分钟前
数据结构面试题【无答案】
c语言·开发语言·数据结构·链表
宸津-代码粉碎机37 分钟前
AI工程化高阶实战|从Demo到生产落地核心架构、全套源码与避坑指南
java·大数据·开发语言·人工智能·python·架构
cmes_love1 小时前
港股Level2历史数据:逐笔成交与分钟线
数据库·oracle
自由能燃气设备1 小时前
燃气热水锅炉/全预混低氮冷凝锅炉哪个品牌好?哪家好?6大商用品牌横评
大数据·数据库·人工智能
智购科技智能售货柜1 小时前
2026自动售货机设备能耗计量系统:从功率监测到能效分析的工程实践~YH
数据库·人工智能·redis·缓存·架构·perl·symfony
云贝贝贝1 小时前
PostgreSQL 生产环境备份恢复与高可用实战
数据库·postgresql