【问题标题】:How do I use NSConditionLock? Or NSCondition如何使用 NSConditionLock?或 NSCondition
【发布时间】:2011-07-15 07:51:37
【问题描述】:

我试图让一个函数等待另一个函数,我想使用 NSCondionLock 来完成此操作。我不是在寻求帮助,而是真的希望有人可以向我展示一个体面的教程或示例来解释 NSConditionLock,或者可能提出更好的方法。

【问题讨论】:

    标签: iphone ios locking conditional-statements


    【解决方案1】:

    编辑:正如@Bonshington 评论的那样,这个答案指的是NSCondition(而不是NSConditionLock):

    - (void) method1 {
    
        [myCondition lock];
        while (!someCheckIsTrue)
            [myCondition wait];
    
    
        // Do something.
    
    
        [myCondition unlock];
    }
    
    - (void) method2 {
    
        [myCondition lock];
    
    
        // Do something.
    
    
        someCheckIsTrue = YES;
        [myCondition signal];
        [myCondition unlock];
    }
    

    someCheckIsTrue 可以是任何东西,它可以是一个简单的 BOOL 变量,甚至可以是 [myArray count] == 0 && color == kColorRed 之类的东西,没关系。重要的是,在一种方法中在您拥有锁时检查条件,而在另一种方法中,您进行更改以使条件变为真在拥有锁时也 .神奇的是waitsignal 部分:wait 实际上解锁了锁并在其他一些名为signal 的线程之后重新获取它。

    【讨论】:

    • 如何申报?它只是 NSConditionLock *lock = [[NSConditionLock alloc] init] 吗?我应该在调用需要同步的两个函数的任何方法中声明它吗?抱歉,如果我没有正确格式化我的评论,这是我第一次真正发布。
    • 您应该在您的类中将其声明为实例变量NSConditionLock *lock;。然后你用lock = [[NSConditionLock alloc] init];在你的init中初始化它,就是这样。此外,在dealloc 中,您只需释放它:[lock release];。或者如果方法在不同的类中,那么你需要在两个方法都可以访问的地方定义锁。
    • @gurooj:首先,方法必须在不同的线程上运行。所以他们可能不会互相打电话,否则你会陷入僵局。现在,首先method1 需要运行并点击wait,然后method2 将使用signal 唤醒它。
    • NSConditionLock 没有等待,信号。它的 NSCondition
    • @MobileMon: No. 引用documentation of signal: 你使用这个方法唤醒一个正在等待条件的线程。 (强调我的)
    【解决方案2】:

    对于那些想要在这里上一个示例测试类的人,我发布了我所做的事情,以了解 NSCondition 的工作原理。

    // --- MyTestClass.h File --- //
    @interface MyTestClass
    
    - (void)startTest;
    
    @end
    
    // --- MyTestClass.m File --- //
    @implementation MyTestClass
    {
        NSCondition *_myCondition;
        BOOL _someCheckIsTrue;
    }
    
    - (id)init
    {
        self = [super init];
        if (self) 
        {
            _someCheckIsTrue = NO;
            _myCondition = [[NSCondition alloc] init];
        }
        return self;
    }
    
    #pragma mark Public Methods
    
    - (void)startTest
    {
        [self performSelectorInBackground:@selector(_method1) withObject:nil];
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            sleep(5);
            [self performSelectorInBackground:@selector(_method2) withObject:nil];
        });
    }
    
    #pragma mark Private Methods
    
    - (void)_method1
    {
        NSLog(@"STARTING METHOD 1");
    
        NSLog(@"WILL LOCK METHOD 1");
        [_myCondition lock];
        NSLog(@"DID LOCK METHOD 1");
    
        while (!_someCheckIsTrue)
        {
            NSLog(@"WILL WAIT METHOD 1");
            [_myCondition wait];
            NSLog(@"DID WAIT METHOD 1");
        }
    
        NSLog(@"WILL UNLOCK METHOD 1");
        [_myCondition unlock];
        NSLog(@"DID UNLOCK METHOD 1");
    
        NSLog(@"ENDING METHOD 1");
    }
    
    - (void)_method2
    {
        NSLog(@"STARTING METHOD 2");
    
        NSLog(@"WILL LOCK METHOD 2");
        [_myCondition lock];
        NSLog(@"DID LOCK METHOD 2");
    
        _someCheckIsTrue = YES;
    
        NSLog(@"WILL SIGNAL METHOD 2");
        [_myCondition signal];
        NSLog(@"DID SIGNAL METHOD 2");
    
        NSLog(@"WILL UNLOCK METHOD 2");
        [_myCondition unlock];
        NSLog(@"DID UNLOCK METHOD 2");
    }
    
    @end
    
    
    // --- Output --- //
    /*
    2012-11-14 11:01:21.416 MyApp[8375:3907] STARTING METHOD 1
    2012-11-14 11:01:21.418 MyApp[8375:3907] WILL LOCK METHOD 1
    2012-11-14 11:01:21.419 MyApp[8375:3907] DID LOCK METHOD 1
    2012-11-14 11:01:21.421 MyApp[8375:3907] WILL WAIT METHOD 1
    2012-11-14 11:01:26.418 MyApp[8375:4807] STARTING METHOD 2
    2012-11-14 11:01:26.419 MyApp[8375:4807] WILL LOCK METHOD 2
    2012-11-14 11:01:26.419 MyApp[8375:4807] DID LOCK METHOD 2
    2012-11-14 11:01:26.420 MyApp[8375:4807] WILL SIGNAL METHOD 2
    2012-11-14 11:01:26.420 MyApp[8375:4807] DID SIGNAL METHOD 2
    2012-11-14 11:01:26.421 MyApp[8375:4807] WILL UNLOCK METHOD 2
    2012-11-14 11:01:26.421 MyApp[8375:3907] DID WAIT METHOD 1
    2012-11-14 11:01:26.421 MyApp[8375:4807] DID UNLOCK METHOD 2
    2012-11-14 11:01:26.422 MyApp[8375:3907] WILL UNLOCK METHOD 1
    2012-11-14 11:01:26.423 MyApp[8375:3907] DID UNLOCK METHOD 1
    2012-11-14 11:01:26.423 MyApp[8375:3907] ENDING METHOD 1
    */
    

    【讨论】:

    • 谢谢,但您的示例并未说明为什么使用while (!_someCheckIsTrue) 而不是if (!_someCheckIsTrue)
    【解决方案3】:

    Swift 5 版本的 @vilanovi 来自 Playground 的回答:

    let myCondition = NSCondition()
    
    var someCheckIsTrue = false
    
    func method1() {
        print("STARTING METHOD 1")
    
        print("WILL LOCK METHOD 1")
        myCondition.lock()
        print("DID LOCK METHOD 1")
    
        while (!someCheckIsTrue) {
            print("WILL WAIT METHOD 1")
            myCondition.wait()
            print("DID WAIT METHOD 1")
        }
    
        print("WILL UNLOCK METHOD 1")
        myCondition.unlock()
        print("DID UNLOCK METHOD 1")
    
        print("ENDING METHOD 1")
    }
    
    func method2() {
        print("STARTING METHOD 2")
    
        print("WILL LOCK METHOD 2")
        myCondition.lock()
        print("DID LOCK METHOD 2")
    
        someCheckIsTrue = true
    
        print("WILL SIGNAL METHOD 2")
        myCondition.signal()
        print("DID SIGNAL METHOD 2")
    
        print("WILL UNLOCK METHOD 2")
        myCondition.unlock()
        print("DID UNLOCK METHOD 2")
    
        print("ENDING METHOD 2")
    }
    
    DispatchQueue.global().async {
        method1()
    }
    
    DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 0.5) {
        method2()
    }
    

    【讨论】:

    • 为什么method2()会锁定和解锁?需要吗?
    【解决方案4】:

    NSConditionLock 示例程序。

    #import <Foundation/Foundation.h>
    
    #define IDLE 0
    #define START 1
    #define TASK_1_FINISHED 2
    #define TASK_2_FINISHED 3
    #define CLEANUP_FINISHED 4
    
    #define SHARED_DATA_LENGTH 1024 * 1024 * 1024
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            NSConditionLock *lock = [[NSConditionLock alloc] initWithCondition:IDLE];
            char *shared_data = calloc(SHARED_DATA_LENGTH, sizeof(char));
    
            [NSThread detachNewThreadWithBlock:^{
                [lock lockWhenCondition:START];
    
                NSLog(@"[Thread-1]: Task 1 started...");
                for (size_t i = 0; i < SHARED_DATA_LENGTH; i++) {
                    shared_data[i] = 0x00;
                }
                [lock unlockWithCondition:TASK_1_FINISHED];
            }];
    
            [NSThread detachNewThreadWithBlock:^{
                [lock lockWhenCondition:TASK_1_FINISHED];
                NSLog(@"[Thread-2]: Task 2 started...");
                for (size_t i = 0; i < SHARED_DATA_LENGTH; i++) {
                    char c = shared_data[i];
                    shared_data[i] = ~c;
                }
                [lock unlockWithCondition:TASK_2_FINISHED];
            }];
    
            [NSThread detachNewThreadWithBlock:^{
                [lock lockWhenCondition:TASK_2_FINISHED];
    
                NSLog(@"[Thread-3]: Cleaning up...");
                free(shared_data);
                [lock unlockWithCondition:CLEANUP_FINISHED];
            }];
    
            NSLog(@"[Thread-main]: Threads set up. Waiting for 2 task to finish");
            [lock unlockWithCondition:START];
            [lock lockWhenCondition:CLEANUP_FINISHED];
            NSLog(@"[Thread-main]: Completed");
        }
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多