我正在编写一个Objective-C类,我希望它是线程安全的。要做到这一点,我使用pthreads和pthread_rwlock
(使用@synchronized
是过度的,我想学习更多关于pthreads)。锁定在指定init
方法的对象中,并在dealloc
中销毁。我有三种操作锁的方法; readLock
,writeLock
,unlock
。这三种方法只调用相关的pthread函数,目前没有其他任何东西。
以下是两个对象方法,两者都需要writeLock:
-(void)addValue:(const void *)buffer
{
[self writeLock];
NSUInteger lastIndex = self.lastIndex;
[self setValue:buffer atIndex:(lastIndex == NSNotFound) ? 0 : lastIndex+1];
[self unlock];
}
-(void)setValue:(const void *)buffer atIndex:(NSUInteger)index
{
[self writeLock];
//do work here
[self unlock];
}
调用setAddValue:
将首先获得写锁定,然后调用setValue:atIndex:
,它还将尝试获取写锁定。文档指出发生这种情况时行为未定义。因此,在尝试获取锁之前,如何检查线程是否有锁?
(我可以确保关键部分不会调用触发另一个锁定请求,但这意味着代码重复,我想让我的代码保持DRY)。
答案 0 :(得分:2)
不完全清楚你正在使用什么样的锁。你表明你正在使用pthreads和读/写锁,所以我得出的结论是你正在使用pthread_rwlock。
如果这是真的,那么你应该可以在锁上使用pthread_rwlock_trywrlock
。从手册页中,
如果成功,则pthread_rwlock_wrlock()和pthread_rwlock_trywrlock() 函数将返回零。否则,将返回错误号 表示错误。
并且,其中一个错误是:
[EDEADLK]调用线程已拥有读/写锁 (用于阅读或写作)。
因此,我相信您应该能够致电pthread_rwlock_trywrlock()
并且您将获得成功,如果另一个线程有锁定,它将返回EBUSY
,否则您将获得EDEADLK
当前线程有锁。
答案 1 :(得分:0)
首先,仅包含一个操作的关键部分是无用的。关键是要使不同的事物相互同步。 (你确实有效地使整数成为原子,但这可能不是完整的意图。)
其次,您已经知道在后一个关键部分中有写锁定,因此无需检查它是否存在。只是在写作时不要尝试读锁定。
解决方案可能是将readLock
和writeLock
调用移动到调用函数中,但不知道更多内容是不可能的。
(这也可能通过减少总操作次数来降低锁定的性能成本,因为您不会锁定然后立即解锁。可能您不需要直接在pthreads级别工作。)
答案 2 :(得分:0)
便携式程序不能依赖于实现来告诉调用者它已经拥有写锁定。相反,您需要执行类似这样的操作来使用递归写锁来包装rwlock:
int wrlock_wrap(pthread_rwlock_t *l, int *cnt)
{
int r = *cnt ? 0 : pthread_rwlock_wrlocK(l);
if (!r) ++*cnt;
return r;
}
int wrunlock_wrap(pthread_rwlock_t *l, int *cnt)
{
--*cnt;
return pthread_rwlock_unlock(l);
}
您可以将计数保留在pthread_rwlock_t
旁边的任何位置,例如作为struct / class /的成员。