软件编程3-进程和线程3-线程传参、通信,信号量
本文介绍了多线程编程的关键技术。在参数传递方面,可通过pthread_create的第四个参数向线程传递参数。线程属性分为可连接(需手动回收)和分离(自动回收)两种,分别通过pthread_attr_init等接口设置。线程通信主要通过共享全局变量实现,但需使用互斥锁(pthread_mutex系列函数)解决资源竞争问题。文章还分析了死锁的四个必要条件及避免方法,并介绍了信号量(sem_init等
一、线程的传参
1. 可以通过pthread_create第四个参数实现对线程内部的传参
二、线程的属性
1、线程属性:
加入属性:线程结束需要pthread_join手动回收
分离属性:线程结束后系统自动回收线程空间
2、函数接口:
1) pthread_attr_init
2) pthread_attr_setdetachstate
3) pthread_attr_destroy
3、区别
1)分离属性:
线程结束后,操作系统自动回收空间
不需要手动调用pthread_join回收线程空间
2)加入属性:
可以回收到线程结束的状态
可以完成线程间的同步
三、线程间的通信
1、概念:
多线程之间传递信息
2、方式:
采用全局变量实现
原因:
进程是操作系统资源分配的最小单元
每个进程空间独立的,包含文本段+数据段(全局变量)+系统数据段
一个进程中的多个线程独享栈空间,文本段、数据段、堆区进程多线程共享
图解:
- 注意:
- 多线程同时操作共享空间会引发资源竞争,需要加上互斥锁解决资源竞争问题
3、互斥锁
1)概念
- 解决资源竞争的一种方式,可以看成是一种资源。
- 只能加锁一次,加锁期间不能再次加锁,也不能强制占有一个已经加锁的锁资源,必须等待锁资源释放,也就是解锁后才能继续操作该锁
- 加锁和解锁中间的代码称为临界代码,也称为临界区
- 只能防止多个线程对资源的竞争,但不能决定代码的先后执行顺序
- 原子操作:CPU执行原子操作时无法切换调度任务
2) 使用方式:
- 定义互斥锁(全局变量)
- 对锁初始化
- 操作全局资源前先加锁
- 如果加锁成功则完成对全局资源操作
- 如果加锁失败则表示有人占用资源,必须等待其余人释放锁资源才能加锁成功
- 直到加锁成功使用该全局资源
3)函数接口:
① pthread_mutex_init
② pthread_mutex_lock
③ pthread_mutex_unlock
④ pthread_mutex_destroy
3、死锁
1)概念:
多线程由于加锁解锁错误导致程序无法继续向下运行的状态称为死锁状态,简称为死锁
2)死锁产生的四个必要条件:
互斥条件
不可剥夺条件
请求保持条件
循环等待条
3)如何避免死锁:
加锁顺序保持一致
使用pthread_mutex_trylock替换pthread_mutex_lock
四、信号量
1、概念:
信号量是一种资源
信号量只能完成四种操作:初始化、销毁、申请、释放
如果信号量资源数为0,申请资源会阻塞等待,直到占用资源的任务释放资源,资源数不为0时
才能申请到资源并继续向下执行
释放资源不会阻塞
2、函数接口
1)sem_init
2)sem_destroy
3)sem_wait
- 注意:
- 申请信号量会让信号量资源数-1
- 如果信号量资源数为0,则会阻塞等待,直到有任务释放资源,才能拿到资源并继续向下执行
4)sem_post
五、练习
题目:编写3个线程任务,线程1循环打印 "A", 线程2循环打印"B",线程3循环打印"C",要求打印出的字符顺序总为ABC
1、代码实现
#include "../head.h"
char ch = 0;
sem_t sem_w;void *thread1(void *arg)
{
while (1)
{
//我已知要输出的内容,不用从终端接,就不需要读资源
sem_wait(&sem_w);
ch = 'A';sem_wait(&sem_w);
ch = 'B';sem_wait(&sem_w);
ch = 'C';
}return NULL;
}
void *thread2(void *arg)
{
while (1)
{
printf("%c\n",ch);
sem_post(&sem_w);
}return NULL;
}int main(void)
{
pthread_t tid1;
pthread_t tid2;sem_init(&sem_w,0,1);
pthread_create(&tid1,NULL,thread1,NULL);
pthread_create(&tid2,NULL,thread2,NULL);pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
sem_destroy(&sem_w);
return 0;
}
如果结果出不来,是因为输出结果太快,可以用sleep解决
更多推荐
所有评论(0)