How do I use NSConditionLock? Or NSCondition

前端 未结 4 1013
攒了一身酷
攒了一身酷 2020-12-02 08:26

I am try to make one function wait for another, and I would like to use NSCondionLock in order to accomplish this. I am not asking for help, but really hoping someone could

相关标签:
4条回答
  • 2020-12-02 08:54

    EDIT: as @Bonshington commented, this answer refers to NSCondition (as opposed to 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];
    }
    

    The someCheckIsTrue can be anything, it could be a simple BOOL variable or even something like [myArray count] == 0 && color == kColorRed, it doesn't matter. It only matters that in one method you check for a condition while you have the lock and in another method you make changes that can make the condition become true also while having the lock. The magic is the wait and signal part: the wait actually unlocks the lock and reacquires it after some other thread called signal.

    0 讨论(0)
  • 2020-12-02 09:02

    NSConditionLock example program.

    #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;
    }
    
    0 讨论(0)
  • 2020-12-02 09:12

    For those that want a sample test class here I post what I did to play around and understand how NSCondition works.

    // --- 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
    */
    
    0 讨论(0)
  • 2020-12-02 09:16

    Swift 5 version of @vilanovi answer from 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()
    }
    
    0 讨论(0)
提交回复
热议问题