最近要做一个FS多线程优化的项目:初步想法是将原来的静态锁去掉,换成并发性能更好的读写锁。我这里只是做个知识储备。
我们先看下源码:
int
__pthread_rwlock_init (rwlock, attr)
pthread_rwlock_t *rwlock;
const pthread_rwlockattr_t *attr;
{
const struct pthread_rwlockattr *iattr;
iattr = ((const struct pthread_rwlockattr *) attr) ?: &default_attr;
rwlock->__data.__lock = 0;
rwlock->__data.__flags
= iattr->lockkind == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP;
rwlock->__data.__nr_readers = 0;
rwlock->__data.__writer = 0;
rwlock->__data.__readers_wakeup = 0;
rwlock->__data.__writer_wakeup = 0;
rwlock->__data.__nr_readers_queued = 0;
rwlock->__data.__nr_writers_queued = 0;
return 0;
}
pthread_rwlock_init初始化锁,这里值得一提的是读写锁的默认属性PTHREAD_RWLOCK_DEFAULT_NP,这个值之间决定__flags字段。
如果你想要用到写优先的特性,所以你必须用到PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,而非一些博文上所说的
其他值。
/* Acquire read lock for RWLOCK. */
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;
}
我们看到这个判断
/* 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))
__flags在这里起到了作用。下面是pthread_rwlock_wrlock,pthread_rwlock_unlock源码
/* Acquire write lock for RWLOCK. */
int
__pthread_rwlock_wrlock (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 and no reader. */
if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0)
{
/* Mark self as writer. */
rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid);
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 writer. */
if (++rwlock->__data.__nr_writers_queued == 0)
{
/* Overflow on number of queued writers. */
--rwlock->__data.__nr_writers_queued;
result = EAGAIN;
break;
}
int waitval = rwlock->__data.__writer_wakeup;
/* Free the lock. */
lll_mutex_unlock (rwlock->__data.__lock);
/* Wait for the writer or reader(s) to finish. */
lll_futex_wait (&rwlock->__data.__writer_wakeup, waitval);
/* Get the lock. */
lll_mutex_lock (rwlock->__data.__lock);
/* To start over again, remove the thread from the writer list. */
--rwlock->__data.__nr_writers_queued;
}
/* We are done, free the lock. */
lll_mutex_unlock (rwlock->__data.__lock);
return result;
}
/* Unlock RWLOCK. */
int
__pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
{
lll_mutex_lock (rwlock->__data.__lock);
if (rwlock->__data.__writer)
rwlock->__data.__writer = 0;
else
--rwlock->__data.__nr_readers;
if (rwlock->__data.__nr_readers == 0)
{
if (rwlock->__data.__nr_writers_queued)
{
++rwlock->__data.__writer_wakeup;
lll_mutex_unlock (rwlock->__data.__lock);
lll_futex_wake (&rwlock->__data.__writer_wakeup, 1);
return 0;
}
else if (rwlock->__data.__nr_readers_queued)
{
++rwlock->__data.__readers_wakeup;
lll_mutex_unlock (rwlock->__data.__lock);
lll_futex_wake (&rwlock->__data.__readers_wakeup, INT_MAX);
return 0;
}
}
lll_mutex_unlock (rwlock->__data.__lock);
return 0;
}
从源码看出:1.读写锁无法递归,否则会EDEADLK;2.如果你想用到写优先,你必须设置属性PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP。
下篇博文:使用Doxygen生成函数调用图。