【问题标题】:NSCondition: Recursive Locking?NSCondition:递归锁定?
【发布时间】:2012-02-03 14:32:22
【问题描述】:

我正在创建一个阻塞队列,由大约 10 个工作线程同时访问。队列的基本实现是这样的:

-(void) enqueue:(__strong id)value
{
    [_mutex lock];

    while ([self size] == _maxSize) {
        [_mutex wait];
    }

    [_queue enqueue:value];
    [_mutex signal];
    [_mutex unlock];
}

-(id) dequeue
{    
    [_mutex lock];

    while ([self isEmpty]) {
        [_mutex wait];
    }

    id value = [_queue dequeue];
    [_mutex broadcast];

    [_mutex unlock];
    return value;
}

其中_mutexNSCondition。问题来自-isEmpty-size 方法:

-(int) size
{
    @try {
        [_mutex lock];

        return [_queue size];
    }
    @finally {
        [_mutex unlock];        
    }
}

-(BOOL) isEmpty
{
    @try {
        [_mutex lock];

        return [_queue isEmpty];
    }
    @finally {    
        [_mutex unlock];
    }
}

因为它们需要对互斥体进行锁定以确保没有数据损坏,所以它会使程序陷入死锁,因为NSCondition 不会递归锁定。但是,如果我将实现更改为以下内容:

-(void) enqueue:(__strong id)value
{
    while ([self size] == _maxSize) {
        [_mutex lock];
        [_mutex wait];
        [_mutex unlock];
    }

    [_mutex lock];
    [_queue enqueue:value];
    [_mutex signal];
    [_mutex unlock];
}

-(id) dequeue
{
    while ([self isEmpty]) {
        [_mutex lock];
        [_mutex wait];
        [_mutex unlock];
    }

    [_mutex lock]; // when I require the lock here, another thread has already dequeued the object
    id value = [_queue dequeue];
    [_mutex broadcast];

    [_mutex unlock];
    return value;
}

然后程序不会死锁,但是,当我重新获得锁时,另一个工作人员已经将我需要的对象出队。关于如何使 NSCondition 递归的任何想法?

【问题讨论】:

    标签: objective-c multithreading mutex semaphore nscondition


    【解决方案1】:

    我一般使用以下模式:

    -(int)primitiveSize
    {
      return [_queue size];
    }
    

    ObjC 中以 primitive 为前缀的方法(来自 Core Data 命名传统)表明它们没有副作用,没有有趣的业务,没有转换,只是给我的价值。这样,您可以在已经获得锁而不放弃封装的情况下使用primitiveSize

    这比创建递归互斥锁要快得多。

    【讨论】:

    • 我没想到。感谢您跳出框框思考!
    【解决方案2】:

    我已经为实现递归互斥锁的 NSCondition 类实现了一个直接替换:https://github.com/bradley219/NSRecursiveCondition

    【讨论】: