多线程同步的四种方式(史上最详细+用例) 多线程同步的四种方式 对于多线程程序来说,同步是指在一定的时间内只允许某一个线程来访问某个资源。而在此时间内,不允许其他的线程访问该资源。可以通过互斥锁(Mutex)、条件变量(condition variable)、读写锁(reader-writer lock)、信号量(semaphore)来同步资源。 互斥锁(Mutex) 互斥量是最简单的同步机制,即互斥锁。多个进程(线程)均可以访问到一个互斥量,通过对互斥量加锁,从而来保护一个临界区,防止其它进程(线程)同时进入临界区,保护临界资源互斥访问。 互斥锁需要满足三个条件: 互斥 不同线程的临界区没有重叠 无死锁 如果一个线程正在尝试获得一个锁,那么总会成功地获得这个锁。若线程A调用lock()但是无法获得锁,则一定存在其他线程正在无穷次地执行临界区。 无饥饿 每一个试图获得锁的线程最终都能成功。 条件变量(condition variable) 生产者消费者问题:每次生产一个商品,发一个信号,告诉消费者“我生产商品了,快来消费”,消费者拿到生产者的条件变量后每次消费两个商品,然后发出信号“我消费了商品,你可以生产了”–_–(发的这个信号是一个条件变量,通过发送这个信号可以唤醒阻塞的线程,收到信号后,不满足需求也会继续阻塞) 为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起;条件变量是线程的另一种同步机制,它和互斥量是一起使用的。互斥量的目的就是为了加锁,而条件变量的结合,使得线程能够以等待的状态来迎接特定的条件发生,而不需要频繁查询锁。 读写锁(reader-writer lock) 前面介绍的互斥量加锁要么是锁状态,要么就是不加锁状态。而且只有一次只有一个线程可以对其加锁。这样的目的是为了防止变量被不同的线程修改。但是如果有线程只是想读而不会去写的话,这有不会导致变量被修改。但是如果是互斥量加锁,则读写都没有办法。这种场景不能使用互斥量,必须使用读写锁。 读写锁可以有3种状态: 读模式下加锁状态 写模式下加锁状态 不加锁状态 一次只有一个线程可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁。当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞。当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权。但是任何希望以写模式对此锁进行加锁的线程都会阻塞。直到所有的线程释放它们的读锁为止。 读写锁非常适合于对数据结构读的次数大于写的情况。当读写锁在写模式下时,它所保护的数据结构就可以被安全地修改,因为一次只有一个线程可以在写模式下拥有这个锁。 读写锁也叫做共享互斥锁。当读写锁是读模式锁住的,就可以说是以共享模式锁住的。当它是写模式锁住的时候,就可以说成是以互斥模式锁住的。 #include <pthread.h> Int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); Int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); 读写锁通过调用pthread_rwlock_init进行初始化。在释放读写锁占有的内存之前,需要调用pthread_rwlock_destroy做清理工作。如果pthread_rwlock_init为读写锁分配了资源,pthread_rwlock_destroy将释放这些资源。如果在调用pthread_rwlock_destroy之前就释放了读写锁占用的内存空间。那么分配给这个锁的资源就会丢失。 要在读模式下锁定读写锁,需要调用pthread_rwlock_rdlock,要在写模式下锁定读写锁,需要调用pthread_rwlock_wrlock。不管以何种方式锁住读写锁。都可以调用pthread_rwlock_unlock进行解锁。 Int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); Int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); Int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); 信号量(semaphore) 在生产者消费者模型中,对任务数量的记录就可以使用信号量来做。可以理解为带计数的条件变量。当信号量的值小于0时,工作进程或者线程就会阻塞,等待物品到来。当生产者生产一个物品,会将信号量值加1操作。 这是会唤醒在信号量上阻塞的进程或者线程,它们去争抢物品。 这里用一个读写文件作为例子: 首先需要用sem_init(); 初始化sem_t型变量,并设置初始信号量。比如设置为1. 每次调用sem_wait(sem_t *); 信号量减一,当调用sem_post(sem_t *); 信号量加一。 当信号量为0时,sem_wait(); 函数阻塞,等待信号量 >0 时,才进行。
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/17947.html