线程同步
一、为什么需要线程同步?
1.对共享资源进行保护。这里的共享资源是指多个线程都会进行访问的资源。
2.解决数据一致性问题。当一个线程可以修改的变量,其它的线程也可以读取或者修改的时候,这个时候就存在数据一致性的问题,需要对这些线程进行同步操作,确保它们在访问变量的存储内容时不会访问到无效的值。本质在于进程中的多个线程对共享资源的并发访问(同时访问)。
二、线程同步机制
1.互斥锁
在访问共享资源前对互斥锁进行上锁,在访问完成后释放互斥锁(解锁);互斥锁上锁之后,其它线程试图再次加锁都会被阻塞,直到当前线程释放互斥锁。
在我们的程序设计当中,只有将所有线程访问共享资源都设计成相同的数据访问规则,互斥锁才能正常工作。如果允许其中的某个线程在没有得到锁的情况下也可以访问共享资源,那么即使其它的线程在使用共享资源前都申请锁,也还是会出现数据不一致的问题。
互斥锁的基本操作
(1)初始化
互斥锁使用 pthread_mutex_t 数据类型表示,在使用互斥锁之前,必须首先对它进行初始化操作,可以使用两种方式对互斥锁进行初始化操作。
(2)加锁和解锁
2.条件变量
条件变量用于自动阻塞线程,直到某个特定事件发送或某个条件满足为止。通常情况下,条件变量是和互斥锁一起搭配使用的。使用条件变量主要包括两个动作:
3.自旋锁
自旋锁与互斥锁相似,但是互斥锁在无法获取到锁时会让线程陷入阻塞状态;而自旋锁在无法获取到锁时将会在原地“自旋”(调用者一直在循环查看该自旋锁的持有者是否已经释放了锁)等待。
自旋锁的缺点:
(1)占用CPU,处于“自旋”的线程一直在占用CPU运行而迟迟得不到锁。
(2)对同一自旋锁加锁两次必然会导致死锁。
4.读写锁(共享互斥锁)
读写锁有3 种状态:读模式下的加锁状态(以下简称读加锁状态)、写模式下的加锁状态(以下简称写加锁状态)和
读写锁有如下两个规则: