网络编程-线程同步技术

本文介绍了线程同步的重要性,如互斥锁用于保证共享资源的独占访问,防止数据冲突。接着讨论了死锁问题,以及如何通过读写锁提高并发性能,特别是在读操作多于写操作的场景。此外,还探讨了生产者消费者模型,利用条件变量和信号量来协调生产者和消费者的动作,确保资源的有效利用和避免阻塞。最后,提到了信号量在控制资源数量和防止过度生产方面的作用。
摘要由CSDN通过智能技术生成

为什么需要线程同步?

确保共享数据在某个时间点由某个线程单独执行,而不是一起执行。

一.互斥锁

1.互斥锁定义

线程A访问共享资源步骤:

A对共享资源上锁-A访问共享资源-A释放锁;

此时共享资源没有被上锁,才能由其他线程进行访问,在A访问期间,其他线程将被阻塞直到A释放锁。

2. 互斥锁相关函数

首先是初始化一个锁,然后销毁一个锁,加锁解锁操作。

要和线程操作函数以及信号量操作函数区别起来。

3.pthread_mutex_init

pthread_mutex_trylock函数在线程尝试加锁失败时并不会阻塞,而是直接返回。

下图是多线程卖票程序回调函数:

在主线程开始和结束分别初始化和销毁了一个互斥锁。

然后创建了三个线程,分别将此回调函数作为参数传到线程创建函数中,接着用线程分离技术自动回收多余线程资源。

如图所示,用了while(1)循环处理逻辑,每次进入循环线程只会卖一张票,然后再去竞争锁。

二. 死锁

三. 读写锁

如图所示,读写锁可以单独控制加的读和写的锁,对于很多业务来说,读的操作较多,而写的操作较少,读写锁效率就较高。

示例:3个线程写,5个线程读

3个线程的回调函数使用写锁去上锁解锁,5个线程使用读锁去上锁解锁。

四. 生产者消费者模型

生产线程生产商品,放到共享内存中,消费线程从共享线程中取商品。

其中有个注意点:当生产线程生产足够多的商品时,应该通知消费线程去消费,而生产线程会阻塞;

当消费线程消费足够多的商品时,应该通知生产线程去生产,消费线程会暂时阻塞。

解决方法:条件变量和信号量。

共享内存存储数据可以用链表等数据结构。

五.条件变量

wait函数是等待,就是阻塞指定时长线程,而signal函数会唤醒一个正在等待的线程。broadcast唤醒所有的线程。

上图是消费者模型,当没有数据的时候,调用wait条件变量函数阻塞所有消费者线程,并自动释放锁,

然后生产者线程

会拿到锁,进行生产,每生产一个都会调用signal条件变量函数,他会唤醒正在阻塞中的消费线程去消费,

六. 信号量

疑问?有了互斥锁和条件变量,为什么还需要信号量,之前程序不是跑的很好吗?

sem_wait函数会使信号量减1,

sem_timeddwait当为0的时候会阻塞指定时长;

sem_post函数会使信号量加1。

sem_init函数pshared值为0则代表在线程间共享,不为0说明在进程间共享。

伪代码如下:

生产者信号量初始化为8,消费者信号量初始化为0;在生产者生产的时候会使生产者信号量减1,并使消费者信号量加1,消费者线程解除阻塞,

消费者信号量减1,并将生产者信号量加1。

就是说在此模型中,生产者不会一直生产下去,如果不消费,那我最多生产8个就停了。

是不是很熟悉,像资本社会一样,拼命生产,无人消费就会引发经济危机,招了那么多美女主播看似蒸蒸日上,结果大家没钱没观众,那不就破产了吗,程序员不就失业了嘛。

有信号量之后在生产者消费者模型中就不需要条件变量了。

如上图所示,消费者模型中不需要再判断有没有商品了,也不需要sleep函数进行控制竞争了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值