进程读写锁
Pthread_rwlockattr_setshared, 当将process-shared属性设为Pthread_process_shared时,可以得到一个进程间的读写锁,如果process-shared属性设为pthread_process_private, 那么能操作这个读写锁的线程只能是创建这个读写锁的进程中的线程, pthread_shared的默认值为pthread_process_private
int __pthread_rwlock_rdlock (rwlock) pthread_rwlock_t *rwlock; { int result = 0; /* Make sure we are along. */ lll_mutex_lock (rwlock->__data.__lock); while (1) { /* Get the rwlock if there is no writer... */ if (rwlock->__data.__writer == 0 /* ...and if either no writer is waiting or we prefer readers. */ && (!rwlock->__data.__nr_writers_queued || rwlock->__data.__flags == 0)) { /* Increment the reader counter. Avoid overflow. */ if (__builtin_expect (++rwlock->__data.__nr_readers == 0, 0)) { /* Overflow on number of readers. */ --rwlock->__data.__nr_readers; result = EAGAIN; } break; } /* Make sure we are not holding the rwlock as a writer. This is a deadlock situation we recognize and report. */ if (__builtin_expect (rwlock->__data.__writer == THREAD_GETMEM (THREAD_SELF, tid), 0)) { result = EDEADLK; break; } /* Remember that we are a reader. */ if (__builtin_expect (++rwlock->__data.__nr_readers_queued == 0, 0)) { /* Overflow on number of queued readers. */ --rwlock->__data.__nr_readers_queued; result = EAGAIN; break; } int waitval = rwlock->__data.__readers_wakeup; /* Free the lock. */ lll_mutex_unlock (rwlock->__data.__lock); /* Wait for the writer to finish. */ lll_futex_wait (&rwlock->__data.__readers_wakeup, waitval); /* Get the lock. */ lll_mutex_lock (rwlock->__data.__lock); --rwlock->__data.__nr_readers_queued; } /* We are done, free the lock. */ lll_mutex_unlock (rwlock->__data.__lock); return result; }
这是进程获取读锁的函数, 占有读写锁的锁后, __pthread_rwlock_rdlock首先看是否满足获取读锁的条件, 如果满足条件, 增加读者数,然后释放读写锁的锁, 然后退出
如果不满足获取读写锁的条件, 将等待的读者数增加, 释放读写锁的锁, 然后将进程睡眠, 等到写者退出时, 将进程唤醒, 重新占有读写锁的锁, 进行循环, 判断是不是满足占有读写锁的条件
写者获取读写锁的方式于此类似
信号量
struct semaphore { spinlock_t lock; unsigned int count; struct list_head wait_list; };
信号量的结构包含一个自旋锁,一个表示信号量的值count,和一个等待信号量的队列
对于信号量的操作是up和down函数
void up(struct semaphore *sem) { unsigned long flags; spin_lock_irqsave(&sem->lock, flags); if (likely(list_empty(&sem->wait_list))) sem->count++; else __up(sem); spin_unlock_irqrestore(&sem->lock, flags); }
Up函数检查信号量的等待队列是否为空, 如果没有等待的进程, 增加信号量, 如果有等待的进程, 唤醒等待的第一个进程
自旋锁等待的特性是不可中断的. 一旦调用 spin_lock, 你将自旋直到锁变为可用,所以持有自旋锁的程序的一个很重要的一点是不能睡眠
自旋锁需要尽可能短地时间去持有, 一个进程持有自旋锁的时间越长, 另一个进程等待释放的时间就越长
信号量中up函数中调用的spin_lock_irqsave函数是禁止在持有自旋锁时中断的, 并且会将中断状态保存在flags中
在down函数中调用__down, 如果信号量为0, __down会把当前进程加入等待列表, 然后解除该进程对信号量的锁, 调用schedule_timeout使进程睡眠, 超时唤醒后, 再对信号量加锁,进入循环