继上篇。这篇介绍的几种使用的较少。
读写锁
读写锁与互斥锁类似。不过读写锁允许更高的并行性。读写锁可以有三种状态:读锁、写锁或者不加锁状态。一次仅有一个线程可以占有写锁,但是可以有多个线程占有读锁。
当读写锁状态是写加锁状态时,任何试图对这个锁进行加锁的操作都会使得线程阻塞。而当读写锁状态是读加锁状态时,试图对读写锁进行读加锁的操作可以获得访问权,但任何试图对读写锁进行写加锁的操作都会阻塞线程。
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
以上三个函数分别执行对读写锁的读加锁、写加锁和解锁。与互斥锁类似,读写锁同样可以尝试加锁
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
读写锁通常用在对数据结构读操作次数远大于写操作次数的情况。
自旋锁
自旋锁通常不用在用户层而是用在底层来实现其他类型的锁。自旋锁与互斥锁类似,但是在获取锁之前并不会使进程阻塞,而是一直处于忙等阻塞状态。自旋锁可用于以下状态:锁被持有时间短,而且线程并不希望在重新调度上花费太多成本。函数如下:
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
int pthread_spin_unlock(pthread_spinlock_t *lock);
屏障
屏障是用户协调多个线程并行工作的同步机制。屏障允许各个线程等待直到合作线程都到同一点。这里还是举一个例子来说明
pthread_barrier_t b;
pthread_barrier_init(&b, NULL,s_pthreads+1);
for(i=0;i<s_pthreads;i++)
pthread_barrier_create(&tid,NULL,thr_fn, (void *)(i * n/s_pthreads));
pthread_barrier_wait(&b);
sort(a,a+n);
void thr_fn(void *arg){
int length = arg;
sort(a+length,a+length+n/s_pthreads);
pthread_barrier_wait(&b);
}
这里将一个数组分为s_pthreads个部分,分别排序,再总体排序。这里之所以初始化要将最后一个参数给s_pthreads+1是为了让屏障等待包括主进程在内的所有线程。