2

我正在编写一个我想要线程安全的 Objective-C 类。为此,我使用 pthreads 和 a 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)。

4

3 回答 3

2

不完全清楚您使用的是哪种锁。您表明您正在使用 pthreads 和读/写锁,所以我得出的结论是您正在使用 pthread_rwlock。

如果这是真的,那么你应该可以pthread_rwlock_trywrlock在锁上使用。从手册页,

如果成功,pthread_rwlock_wrlock() 和 pthread_rwlock_trywrlock() 函数将返回零。否则,将返回一个错误号以指示错误。

而且,错误之一是:

[EDEADLK] 调用线程已经拥有读/写锁(用于读或写)。

因此,我相信你应该能够调用pthread_rwlock_trywrlock()并且你会成功,EBUSY如果另一个线程有锁,它会返回,或者EDEADLK如果当前线程有锁,你会得到。

于 2011-04-23T18:55:15.187 回答
0

首先,只包含一个操作的临界区是没有用的。关键是使不同的事物相互同步。(您确实有效地使整数原子化,但这可能不是全部意图。)

其次,您已经知道在后面的关键部分中有写锁,因此无需检查它是否存在。只是不要在写入时尝试读锁。

解决方案可能是将readLockandwriteLock调用移动到调用函数中,但不知道更多就不可能说。

(这也可能通过减少总操作数来降低锁定的性能成本,因为您不会锁定然后立即解锁。可能您不需要直接在 pthreads 级别工作。)

于 2011-04-23T18:37:57.273 回答
0

可移植程序不能依赖实现告诉调用者它已经持有写锁。相反,您需要做这样的事情来用递归写锁包装 rwlocks:

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保存在它存储的位置旁边,例如作为结构/类/其他的成员。

于 2011-04-23T21:31:52.837 回答