互斥锁(mutex)用来确保数据在任何时刻只有一个线程访问,简单的说,就是在访问一个多线程共享数据的时候执行加锁操作,访问完成后执行解锁操作。多线程共享的数据在加锁的情况下,如果有线程试图访问,该线程将被阻塞,直到执行了解锁操作。 在使用互斥锁实现线程同步的时候需要注意的是避免死锁,比如互斥锁变量A和B,线程1对A进行加锁后试图对B进行加锁,此时线程2已经对线程B进行加锁并试图对A进行加锁,这就会造成死锁。 ReadWriteLock与互斥锁类似,但是利用ReadWriteLock能比利用互斥锁实现更高程度的并发。使用互斥锁的时候只有加锁和解锁两种状态,同一时刻只能有一个线程执行了加锁操作。对于ReadWriteLock,存在三种状态,分别是加锁读,加锁写以及解锁状态,同一时刻,只能有一个线程处于加锁写的状态,但是可以有多个线程处于加锁读的状态。 当ReadWriteLock处于写锁的状态,所有的加锁请求,包括写锁和读锁,都会被阻塞,直到写锁被打开。当ReadWriteLock处于读锁的状态,所有的读锁定被允许,如果这时有写锁定请求,会被阻塞直到所有的读锁定状态被打开。另外在读锁定状态下,如果有被阻塞的写锁请求,那么新的读锁定将被阻塞,这是为了避免持久处于读锁定状态使得写等待被饿死。 互斥锁和读写锁都只有两 种状态,锁定和非锁定。相关线程需要通过轮询的方式对状态进行检测从而获得呼哧锁或者读写锁,因此程序运行不够高效。另外如果需要多个线程访问同一共享资 源时,若干个轮询和对于锁状态的判断使得程序更加复杂和低效。正像select替代了低效的轮询,能否有一种机制,使得等待某个条件满足的阻塞的线程能够 被触发。 条件变量是互斥锁和读写锁之外另一种线程同步机制,它允许线程阻塞并等待另一个线程发送信号。条件变量通常与互斥锁一起使用。 假定两个线程通过条件变 量实现同步,两个线程分别为线程A和线程B。条件变量本身需要用互斥锁进行保护。线程A获得互斥锁,从而获得对于条件变量的访问,如果条件变量满足,则立 即释放互斥锁并进行相应的处理。如果条件不满足有两种选择,其一是阻塞直到条件满足后释放互斥锁并进行相应处理,其二是阻塞等待条件满足后释放互斥锁并进 行相应处理,或者超时退出阻塞并释放互斥锁。 线程B的工作相对比较简单,就是获取互斥锁,进行相应的处理,条件变量变成满足后,释放互斥锁,然后通知另外一个线程,条件变量已经满足。如下是条件变量运行机制的简单示例,来自《Advanced Programming in the UNIX® Environment: Second Edition》:
那么线程间同步和定时机制有什么关系那。对于实时的视频服务器来说,需要把媒体数据“准时”的发送给客户端,既不能提前,也不能滞后。这时就可以采用条件变量的原理来实现精确定时,精度可以达到纳秒级别。 在介绍采用条件变量这种定时机制之前,先来看看Linux系统下其他的定时机制。说道定时,首先想到的就是sleep,nanosleep等函数,其实还有一个常用的方法就是采用select。这里有sleep,nanosleep以及select三种定时机制的介绍和对比,结论是select能实现精度更高的定时。作者是在2.4内核下测试的,select能达到10ms以上的精确定时。 条件变量的方法实现定时的机制和select类似,其特点是线程被唤醒的方式有两种,一种是超时唤醒,一种是条件变化后通过事件触发唤醒。 (dqzhangp) |