多线程编程:线程同步

来源:互联网 发布:网络宣传怎么做 编辑:程序博客网 时间:2024/05/17 16:46

前言

多线程编程必须要考虑线程同步问题。线程同步就是,当多个线程共享一个内存的时候,为了保证他们都有一致的数据视图。如果每个线程使用的变量都是其他线程不会读取和修改的,那么就不存在一致性问题。同样的,如果变量是只读的,多个线程同时读取该变量也不会有一致性问题;但是,当一个线程可以修改的变量,其他线程可以读取或者修改的时候,我们就需要对这些线程进行同步,确保它们在访问变量的存储内容的时候不会访问到无效值。为了保证数据安全,下面介绍一些办法

1、互斥量

互斥量本质上是一把锁,在访问共享资源之前对互斥量进行设置加锁,在访问完成后释放(解锁)互斥量。对互斥量进行加锁后,任何试图对互斥量加锁的线程都会被阻塞直到当前线程释放该互斥锁。如果释放互斥量时,有一个以上的线程阻塞,那么该锁上被阻塞的线程都会变成可运行状态,第一个变为运行的线程就可以对互斥量加锁,其他线程就会看到互斥量依然是锁着的,只能回去再次等待它重新变为可用。在这种情况下每次只有一个线程可以运行

note:只有将所有线程都设计成遵守相同数据访问规则的,互斥机制才可以正常工作。

避免死锁:如果线程试图对互斥量加两次互斥锁,那么它自身将会陷入死锁。

2、读写锁

读写锁与互斥量相似,但是读写锁允许更高的并行性。互斥量要么是锁住状态,要么是不加锁状态,而且一次只有一个线程可以对其加锁。读写锁可以有三种状态:读模式下加锁状态,写模式下加锁状态,不加锁状态。一次只有一个线程可以占有写模式的读写锁,但是多个线程可以占有读状态。当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞。当读写锁是读加锁状态时,所有试图以读模式对他进行加锁的线程都将得到访问权,但是任何希望以写模式对此锁进行加锁的线程都会被阻塞,直到所有的线程释放它的读锁为止。

读写锁也叫作共享互斥锁。当读写锁是读模式锁住时,可以说成是以共享模式锁住的;当读写锁是写模式锁住时,可以说成是以互斥模式锁住的。

note:读写锁非常适合读的次数远远大于写的次数的情况下。

3、条件变量

条件变量是线程可用的另一种同步机制。条件变量给多个线程提供了会和的场所。条件变量与互斥量一起使用的时候,允许线程以无竞争的方式等待特定的条件发生。条件本身是由互斥量保护的。线程在改变状态前必须先锁住互斥量。其他线程在获取互斥量之前不会察觉到这种变化,因为互斥量必须锁定后才能计算条件

4、自旋锁

自旋锁与互斥量类似,但他不是通过休眠使线程阻塞,而是在获取锁之前一直处于忙等状态(自旋)阻塞状态。自旋锁可以用于一下情况:锁被持有的时间较短,而且线程并不希望重新调度上花费太多的成本。

自旋锁通常作为底层原语去实现其他类型的锁,当线程等待锁变为可用时,CPU不能做其他任何事情。这也是自旋锁只能够被持有一小段时间的原因。

5、屏障

屏障是用户协调多个线程并行工作的同步机制。屏障允许每个线程等待,直到所有的合作线程都达到某一点,然后从该点继续执行。(允许一个线程等待,直到另外一个线程退出)