日期:2014-05-16  浏览次数:20792 次

Linux/UNIX线程(2)

线程(2)

线程同步

当多个控制线程共享相同内存时,需要确保每个线程看到一致的数据视图。如果每个线程使用的变量都是其他线程不会读取或修改的,那么就不在一致性问题。

当两个或多个线程试图在同一时间修改同一变量时,也需要进行同步。考虑变量递增操作的情况:增量操作通常分三步:

1.      从内存单元读入寄存器

2.      在寄存器中进行变量值的增加

3.      把新的值写回内存单元

互斥量

可以通过使用pthread的互斥接口保护数据,确保同一时间只有一个线程访问数据。互斥量从本质上说是一把锁,在访问资源前对互斥量加锁,在访问完成后释放互斥量上的锁。对互斥量进行加锁以后,任何其他试图再次对互斥量加锁的线程将会被阻塞直到线程释放该互斥锁。

互斥变量用pthread_mutex_t数据类型来表示,在使用互斥量以前,必须首先对其进行初始化,可以把它置为PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量),也可以通过调用pthread_mutex_init函数进行初始化。如果动态分配互斥量,那么释放内存前需要调用pthread_mutex_destroy。用默认属性初始化互斥量,只需要把attr设置为NULL

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t *restrict mutex,constpthread_mutexattr_t *restrict attr);
  intpthread_mutex_destroy(pthread_mutex_t *mutex);

若成功返回0,错误返回错误编号。

对互斥量进行加锁,需要调用pthread_mutex_lock,如果互斥量已经上锁,调用线程将阻塞直到互斥量被解锁。

#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock( pthread_mutex_t *mutex );

int pthread_mutex_unlock(pthread_mutex_t *mutex);

若成功返回0,错误返回错误编号。

如果线程不希望不阻塞,它可以使用pthread_mutex_trylock尝试对互斥量进行加锁。如果调用pthread_mutex_trylock时互斥量处于未锁住状态,那么pthread_mutex_trylock将锁住互斥量,不会出现阻塞并返回0,否则pthread_mutex_trylock就会失败,不能锁住互斥量,而返回EBUSY

避免死锁

如果线程试图对同一个互斥量加锁两次,那么它自身就会陷入死锁状态。

如果程序中使用多个互斥量时,如果允许一个线程一直占有第一个互斥量,并且试图锁住第二个互斥量时处于阻塞状态,但是游泳第二个互斥量的线程也试图锁住第一个互斥量,这是就会发生死锁。

可以通过小心地控制互斥量加锁的顺序来避免死锁的发生。只有一个线程试图以与另一个线程相反的顺序锁住互斥量时,才可能出现死锁。

读写锁

读写锁有三种状态:度模式下加锁状态,写模式下加锁状态,不加锁状态。一次只有一个线程可以占用写模式的读写锁,但是多个线程可以同时占用读模式的读写锁。读写锁非常适合于对数据结构读的次数远大于写的情况。读写锁也叫做共享——独占锁,当读写锁以读模式锁住时,它是以共享模式锁住的;当它以写模式锁住时,它是以独占模式锁住的。

与互斥量一样,读写锁在使用之前必须初始化,在释放它们底层的内存前必须销毁。

#include <pthread.h>

intpthread_rwlock_init(pthread_rwlock* restrict rwlock, const pthread_rwlockattr_t* restrict attr);

int pthread_rwlock_destroy(pthread_rwlock_t* rwlock);

要在读模式下锁定读写锁,需要调用pthread_rwlock_rdlock;要在写模式下锁定读写锁,需要调用pthread_rwlock_wrlock。不管以何种方式锁住读写锁,都可以调用pthreead_rwlock_unlock进行解锁。

#include <pthread.h>

intpthread_rwlock_rdlock(pthread_rwlock_t* rwlock);

int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);

int pthread_rwlock_unlock(pthread_rwlock_t* rwlock);