我有两天时间研究与读写锁相关的东西。 我遇到了一个问题,因为GCD的虚拟线程限制:Dead Lock With `dispatch_barrier`
然后我尝试使用pthread_rwlock_t
来实现rwlock。它就像文章的结尾一样正常运行。
但是当我想将pthread_rwlock_t
的初始化代码移动到static
函数时,就像下面的代码一样,我发现它再次进入死锁状态。
然后我思考了很长时间并进行调试,我发现一件奇怪的事情:
当我从dispatch_once
函数移出init代码(也包含static
)时。一切都好。它太奇怪了,我认为这不是因为GCD的虚拟线程限制。 @ originaluser2
#import <pthread.h>
#define THREAD_ASSERT_ON_ERROR(x_) do { \
_Pragma("clang diagnostic push"); \
_Pragma("clang diagnostic ignored \"-Wunused-variable\""); \
volatile int res = (x_); \
assert(res == 0); \
_Pragma("clang diagnostic pop"); \
} while (0)
static pthread_rwlock_t kRWLock(){
static pthread_rwlock_t _rwlock;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
THREAD_ASSERT_ON_ERROR(pthread_rwlock_init(&_rwlock, NULL));
});
return _rwlock;
}
//#define WILLDEADLOCK //define it will see the deadlock demo
- (void)test
{
dispatch_queue_t queue = dispatch_queue_create("com.test.testasync", DISPATCH_QUEUE_CONCURRENT);
for (NSInteger i=0; i<5000; i++) {
dispatch_async(queue, ^{
#ifdef WILLDEADLOCK
pthread_rwlock_t rwlock = kRWLock();
#else
static pthread_rwlock_t rwlock;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
THREAD_ASSERT_ON_ERROR(pthread_rwlock_init(&rwlock, NULL));
});
#endif
THREAD_ASSERT_ON_ERROR(pthread_rwlock_rdlock(&rwlock));
NSLog(@"rlock1");
NSLog(@"runlock1");
THREAD_ASSERT_ON_ERROR(pthread_rwlock_unlock(&rwlock));
if (i%100==0) {
THREAD_ASSERT_ON_ERROR(pthread_rwlock_wrlock(&rwlock));
NSLog(@"wlock1");
NSLog(@"wunlock1");
THREAD_ASSERT_ON_ERROR(pthread_rwlock_unlock(&rwlock));
}
});
}
dispatch_barrier_sync(queue, ^{});
NSLog(@"completed");
}
答案 0 :(得分:0)
注意:这个问题的作者不允许将答案作为答案发布,所以我已经为他做了。
这是一个愚蠢的问题。我忘了pthread_rwlock_t
是struct
,它会在return
之后复制到新内存。
以下正确的代码:
#import <pthread.h>
#define THREAD_ASSERT_ON_ERROR(x_) do { \
_Pragma("clang diagnostic push"); \
_Pragma("clang diagnostic ignored \"-Wunused-variable\""); \
volatile int res = (x_); \
assert(res == 0); \
_Pragma("clang diagnostic pop"); \
} while (0)
static pthread_rwlock_t *kRWLock(){
static pthread_rwlock_t _rwlock;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
THREAD_ASSERT_ON_ERROR(pthread_rwlock_init(&_rwlock, NULL));
});
return &_rwlock;
}
- (void)test
{
dispatch_queue_t queue = dispatch_queue_create("com.test.testasync", DISPATCH_QUEUE_CONCURRENT);
for (NSInteger i=0; i<5000; i++) {
dispatch_async(queue, ^{
pthread_rwlock_t *rwlock = kRWLock();
THREAD_ASSERT_ON_ERROR(pthread_rwlock_rdlock(rwlock));
NSLog(@"rlock1");
NSLog(@"runlock1");
THREAD_ASSERT_ON_ERROR(pthread_rwlock_unlock(rwlock));
if (i%100==0) {
THREAD_ASSERT_ON_ERROR(pthread_rwlock_wrlock(rwlock));
NSLog(@"wlock1");
NSLog(@"wunlock1");
THREAD_ASSERT_ON_ERROR(pthread_rwlock_unlock(rwlock));
}
});
}
dispatch_barrier_sync(queue, ^{});
NSLog(@"completed");
}