美文网首页
多线程互斥锁

多线程互斥锁

作者: 叫我小黑 | 来源:发表于2018-10-23 20:34 被阅读0次

    在iOS中有几种方法来解决多线程访问同一个内存地址的互斥同步问题:

    一、@synchronized(id anObject),(最简单的方法)

    会自动对参数对象加锁,保证临界区内的代码线程安全

    @synchronized(self) 
    { 
       // 这段代码对其他 @synchronized(self) 都是互斥的 
       // self 指向同一个对象 
    }
    

    二、NSLock

    NSLock对象实现了NSLocking protocol,包含几个方法:

    • lock,加锁
    • unlock,解锁
    • tryLock,尝试加锁,如果失败了,并不会阻塞线程,只是立即返回NO
    • lockBeforeDate:,在指定的date之前暂时阻塞线程(如果没有获取锁的话),如果到期还没有获取锁,则线程被唤醒,函数立即返回NO

    比如:

    NSLock *theLock = [[NSLock alloc] init]; 
    if ([theLock lock]) 
    { 
       //do something here 
       [theLock unlock]; 
    }
    

    三、NSRecursiveLock,递归锁

    NSRecursiveLock,多次调用不会阻塞已获取该锁的线程。

    NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init]; 
    void MyRecursiveFunction(int value) 
    { 
       [theLock lock]; 
       if (value != 0) {
           --value
           MyRecursiveFunction(value); 
        } 
        [theLock unlock]; 
    } 
    MyRecursiveFunction(5);
    

    四、NSConditionLock,条件锁

    NSConditionLock,条件锁,可以设置条件

    //公共部分 
    id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA]; 
    //线程一,生产者 
    while(true) { 
      [condLock lockWhenCondition:NO_DATA]; 
      //生产数据 
      [condLock unlockWithCondition:HAS_DATA]; 
    } 
      //线程二,消费者 
    while (true) 
    { 
      [condLock lockWhenCondition:HAS_DATA]; 
      //消费 
      [condLock unlockWithCondition:NO_DATA];
    }
    

    五、NSDistributedLock,分布锁

    NSDistributedLock,分布锁,文件方式实现,可以跨进程

    • 用tryLock方法获取锁。
    • 用unlock方法释放锁。

    如果一个获取锁的进程在释放锁之前挂了,那么锁就一直得不到释放了,此时可以通过breakLock强行获取锁。
    程序A:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"];
      [lock breakLock];
      [lock tryLock];
      sleep(10);
      [lock unlock];
      NSLog(@"appA: OK");
    });
    

    程序B:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"];
       while (![lock tryLock]) {
         NSLog(@"appB: waiting");
         sleep(1);
       }
       [lock unlock];
       NSLog(@"appB: OK");
    });
    

    先运行程序A,然后立即运行程序B,根据打印你可以清楚的发现,当程序A刚运行的时候,程序B一直处于等待中,当大概10秒过后,程序B便打印出了appB:OK的输出,以上便实现了两上不同程序之间的互斥。/Users/mac/Desktop/earning__是一个文件或文件夹的地址,如果该文件或文件夹不存在,那么在tryLock返回YES时,会自动创建该文件/文件夹。在结束的时候该文件/文件夹会被清除,所以在选择的该路径的时候,应该选择一个不存在的路径,以防止误删了文件。

    六、条件信号量dispatch_semaphore_t

    dispatch_semaphore_t:GCD中信号量,也可以解决资源抢占问题,支持信号通知和信号等待。每当发送一个信号通知,则信号量+1;每当发送一个等待信号时信号量-1,;如果信号量为0则信号会处于等待状态,直到信号量大于0开始执行。

    #import "MYDispatchSemaphoreViewController.h"
    @interface MYDispatchSemaphoreViewController ()
    {
        dispatch_semaphore_t semaphore;
    }
    @end
    @implementation MYDispatchSemaphoreViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        /**
         *  创建一个信号量为1的信号
         *
         */
        semaphore = dispatch_semaphore_create(1);
       }
    - (void)getIamgeName:(NSMutableArray *)imageNames{
        NSString *imageName;
        /**
         *  semaphore:等待信号
         DISPATCH_TIME_FOREVER:等待时间
         wait之后信号量-1,为0
         */
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        if (imageNames.count>0) {
            imageName = [imageNames lastObject];
            [imageNames removeObject:imageName];
        }
        /**
         *  发送一个信号通知,这时候信号量+1,为1
         */
        dispatch_semaphore_signal(semaphore);
    }
    @end
    

    相关文章

      网友评论

          本文标题:多线程互斥锁

          本文链接:https://www.haomeiwen.com/subject/ifqzzftx.html