对于线程同步的理解

线程同步主要是指,在多个线程共同操作同一块内存时,保证线程的执行是顺序的,不会因为抢夺时间片而互相串扰导致与预期结果不符合。
建立起临界区的概念,即我要保证临界区内的代码是一气呵成执行的,不被其他线程所干扰。线程同步主要有4个重要的手段:互斥锁mutex,读写锁rw_lock,条件变量cond,信号量sem。

互斥锁mutex

在临界区的上界进行上锁pthread_mutex_lock,在临界区的下界进行解锁pthread_mutex_unlock。互斥锁可以看做是一个卫生间,别人进去锁上门,那么外边的人想要得到临界区的资源,就必须阻塞等待。但还有一种情况,就是看到卫生间上锁,他不阻塞,直接离开去做自己接下来的事情,这种操作等于pthread_mutex_trylock(),试一下不行就走,返回一个上锁的状态信息。
互斥锁的优点是容易理解,上锁解锁对称代码明晰,缺点是容易造成死锁。通常造成死锁的情况有以下几种

  1. 某线程在进入临界区后进行上锁。该线程在上锁后进入临界区,不小心再次上锁,这时会造成该线程的堵塞,但又无法释放锁资源,造成死锁。多由对别的函数的调用中有对锁的使用造成;
  2. 忘记解锁,即上锁后没有对应的解锁操作;
  3. 线程1对A资源上锁,线程2对B资源上锁,此时线程1访问B,线程2访问A,二者都阻塞且无法释放资源造成死锁;

读写锁

读写锁和互斥锁的区别在于允许对于读操作的并行,适用于读操作很多的情况。读写锁其实是同一个锁,pthread_rwlock_t rwlock,但有两种上锁的情况。一种是上读锁int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);一种是上写锁int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)。如果两个线程分别上读锁和写锁,写锁进入临界区的优先级更高,而读锁会被阻塞。
如果调用读锁rdlock,如果读写锁是打开的,则上锁成功;检查到读锁,那上锁依旧会成功,因为读锁是共享的;如果检查到是写锁,那么上锁失败,处于阻塞;
如果调用wrlock,如果读写锁是打开的,则上锁成功;上锁检查无论是读锁还是写锁,都会阻塞;
读写锁同样有trylock,与上述一致;

条件变量

严格来说条件变量并不是控制线程同步,而是阻塞线程,单使用条件变量无法实现线程同步,需要配合互斥锁。一般和互斥锁一起用于实现生产者-消费者模型。

//线程阻塞函数,哪个线程调用这个函数,就会阻塞
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

通过函数原型可以看出,该函数在阻塞线程的时候,需要一个互斥锁参数,这个互斥锁主要功能是进行线程同步,让线程顺序进入临界区,避免出现数共享资源的数据混乱。该函数会对这个互斥锁做以下几件事情:
1.在阻塞线程时候,如果线程已经对互斥锁mutex上锁,那么会将这把锁打开,这样做是为了避免死锁;
2.当线程解除阻塞的时候,函数内部会帮助这个线程再次将这个mutex互斥锁锁上,继续向下访问临界区;

信号量

int sem_init(sem_t *sem, int pshared, unsigned int value);
// 资源释放, 线程销毁之后调用这个函数即可
// 参数 sem 就是 sem_init() 的第一个参数       
// 第二个参数为0表示线程同步,非0为进程同步
// 第三个参数为初始资源数

一个sem_wait用于资源-1,资源<0则阻塞;一个sem_post用于资源+1

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值