我正在编写一个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:
这也将尝试获取写锁定。文档指出,发生这种情况时的行为是未定义的。因此,在尝试获取锁之前,如何检查线程是否具有锁?
(我可以确保关键部分不会进行触发另一个锁定请求的调用,但这意味着代码重复,我想保持我的代码干燥(。
不完全清楚您使用的锁类型。您指出您正在使用线程和读/写锁定,所以我得出结论,您使用的是pthread_rwlock。
如果这是真的,那么您应该能够在锁上使用pthread_rwlock_trywrlock
。 从手册页,
如果成功,则 pthread_rwlock_wrlock(( 和 pthread_rwlock_trywrlock((函数将返回零。 否则,将返回错误号以指示错误。
而且,其中一个错误是:
[埃迪尔克] 调用线程已拥有读/写锁 (用于阅读或写作(。
因此,我相信你应该能够调用pthread_rwlock_trywrlock()
并且你会成功,如果另一个线程有锁,它会返回EBUSY
,或者如果当前线程有锁,你会得到EDEADLK
。
首先,仅包含一个操作的关键部分是无用的。关键是要同步彼此相对的不同事物。(您确实有效地使整数原子化,但这可能不是全部意图。
其次,您已经知道在后一个关键部分中有写锁定,因此无需检查它是否存在。 只是不要在写入时尝试读锁定。
解决方案可能是将readLock
和writeLock
调用移动到调用函数中,但不知道更多就不可能说。
(这也可能会通过减少总操作数来降低锁定的性能成本,因为您不会锁定然后立即解锁。可能您不需要直接在 pthreads 级别工作。
可移植程序不能依赖实现来告诉调用方它已经持有写锁。相反,您需要执行类似操作以使用递归写锁包装 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
旁边,无论它存储在何处,例如作为结构/类/其他内容的成员。