今天一程序由于读写锁的问题,导致程序一线程死掉。查完了所有的代码,发现加锁之后,均有释放的地方。后来,推测出最有可能的情况:多个线程去读,在写线程加锁时,至少有一个线程没有释放,而后续的读线程继续加锁,导致该写线程饿死。
于是写了以下代码进行测试:
-
#include <stdio.h>
-
#include <pthread.h>
-
#include <time.h>
-
#include <errno.h>
-
#include <string.h>
-
#include <strings.h>
-
-
pthread_rwlock_t link;
-
-
void * t_hand()
-
{
-
-
-
int i = 0;
-
while(1)
-
{
-
printf("++++++++++++++++++++++++++\n");
-
pthread_rwlock_rdlock(&link);
-
printf("---------------------------\n");
-
pthread_rwlock_unlock(&link);
-
printf("=========================== i = %d \n",i++);
-
sleep(1);
-
if( i == 7)
-
break;
-
-
}
-
-
pthread_rwlock_unlock(&link);
-
-
}
-
-
-
-
-
int main(int argc, char ** argv)
-
{
-
int ret = 0;
-
printf(" EBUSY = %d, EINVAL = %d, EAGAIN = %d, EDEADLK = %d\n", EBUSY, EINVAL, EAGAIN, EDEADLK);
-
-
pthread_rwlock_init(&link,NULL);
-
-
-
pthread_t pid ;
-
-
pthread_rwlock_rdlock(&link);
-
-
pthread_create(&pid,NULL,t_hand,NULL);
-
-
sleep(1);
-
-
printf("before wrlock\n");
-
pthread_rwlock_wrlock(&link);
-
printf("after wrlock\n");
-
-
sleep(100);
-
-
}
最后发现输出是以下内容:
-
EBUSY = 16, EINVAL = 22, EAGAIN = 11, EDEADLK = 35
-
++++++++++++++++++++++++++
-
---------------------------
-
=========================== i = 0
-
before wrlock
-
++++++++++++++++++++++++++
-
---------------------------
-
=========================== i = 1
-
++++++++++++++++++++++++++
-
---------------------------
-
=========================== i = 2
-
++++++++++++++++++++++++++
-
---------------------------
-
=========================== i = 3
-
++++++++++++++++++++++++++
-
---------------------------
-
=========================== i = 4
-
++++++++++++++++++++++++++
-
---------------------------
-
=========================== i = 5
-
++++++++++++++++++++++++++
-
---------------------------
-
=========================== i = 6
-
after wrlock
从输出上不难看出,在有一把读锁加上之后,再加上写锁,而后续再有读锁加上时,写锁将一直处于阻塞状态,直到所有的读锁都释放掉。而写锁要加上的条件就是:当前没有读锁。
在将代码修改后:
-
#include <stdio.h>
-
#include <pthread.h>
-
#include <time.h>
-
#include <errno.h>
-
#include <string.h>
-
#include <strings.h>
-
-
-
-
pthread_rwlock_t link;
-
-
-
void * t_hand()
-
{
-
-
-
int i = 0;
-
while(1)
-
{
-
printf("++++++++++++++++++++++++++\n");
-
pthread_rwlock_rdlock(&link);
-
printf("---------------------------\n");
-
pthread_rwlock_unlock(&link);
-
printf("=========================== i = %d \n",i++);
-
sleep(1);
-
if( i == 7)
-
break;
-
-
}
-
-
pthread_rwlock_unlock(&link);
-
-
}
-
-
-
-
-
int main(int argc, char ** argv)
-
{
-
int ret = 0;
-
printf(" EBUSY = %d, EINVAL = %d, EAGAIN = %d, EDEADLK = %d\n", EBUSY, EINVAL, EAGAIN, EDEADLK);
-
-
//pthread_rwlock_init(&link,NULL);
-
-
pthread_rwlockattr_t attr;
-
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
-
pthread_rwlock_init(&link,&attr);
-
-
pthread_t pid ;
-
-
pthread_rwlock_rdlock(&link);
-
-
pthread_create(&pid,NULL,t_hand,NULL);
-
-
sleep(1);
-
-
printf("before wrlock\n");
-
pthread_rwlock_wrlock(&link);
-
printf("after wrlock\n");
-
-
sleep(100);
-
-
}
输出以下内容:
-
EBUSY = 16, EINVAL = 22, EAGAIN = 11, EDEADLK = 35
-
++++++++++++++++++++++++++
-
---------------------------
-
=========================== i = 0
-
before wrlock
-
++++++++++++++++++++++++++
然后一直处于等待状态(此时,已经死锁)。
从上不难看出,一直使用的默认属性对于读写锁的处理方式是:有写不能能,有读不能写但是可读。该策略容易对一些读频繁,写较少的程序造成写线程饿死。
阅读(3274) | 评论(0) | 转发(0) |