iOS 线程锁

来源:互联网 发布:围巾怎么系 知乎 编辑:程序博客网 时间:2024/05/17 21:39

一、使用关键字

1@synchronized (互斥锁)

优点:使用@synchronized关键字可以很方便地创建锁对象,而且不用显式的创建锁对象。

缺点:会隐式添加一个异常处理来保护代码,该异常处理会在异常抛出的时候自动释放互斥锁。而这种隐式的异常处理会带来系统的额外开销,为优化资源,你可以使用锁对象。

二、“ObjectC”语言

      1)NSLock(互斥锁)

2NSRecursiveLock(递归锁)

条件锁,递归或循环方法时使用此方法实现锁,可避免死锁等问题。

3NSConditionLock (条件所)

使用此方法可以指定,只有满足条件的时候才可以解锁。

4NSDistributedLock(分布式锁)

IOS中不需要用到,也没有这个方法,因此本文不作介绍,这里写出来只是想让大家知道有这个锁存在。

 三、C语言

    

    1pthread_mutex_t(互斥锁)

    

    2GCD-信号量(互斥锁

    

    3pthread_cond_t(条件锁)


一、使用关键字:

1@synchronized


// 实例类person

Person *person = [[Person alloc] init];


// 线程A

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    @synchronized(person) {

        [person personA];

        [NSThread sleepForTimeInterval:3]; //线程休眠3

    }

});


// 线程B

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    @synchronized(person) {

        [person personB];

    }

});


关键字@synchronized的使用,锁定的对象为锁的唯一标识,只有标识相同时,才满足互斥。如果线程B锁对象person改为self或其它标识,那么线程B将不会被阻塞。你是否看到@synchronized(self),也是对的。它可以锁任何对象,描述为@synchronized(anObj)

二、ObjectC语言

1)使用NSLock实现锁


// 实例类person

Person *person = [[Person alloc] init];

// 创建锁

NSLock *myLock = [[NSLock alloc] init];


// 线程A

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    [myLock lock];

    [person personA];

    [NSThread sleepForTimeInterval:5];

    [myLock unlock];

});


// 线程B

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    [myLock lock];

    [person personB];

    [myLock unlock];

}); 


程序运行结果:线程B会等待线程A解锁后,才会去执行线程B。如果线程Blockunlock方法去掉之后,则线程B不会被阻塞,这个和synchronized的一样,需要使用同样的锁对象才会互斥。

NSLock类还提供tryLock方法,意思是尝试锁定,当锁定失败时,不会阻塞进程,而是会返回NO。你也可以使用lockBeforeDate:方法,意思是在指定时间之前尝试锁定,如果在指定时间前都不能锁定,也是会返回NO

注意:锁定(lock)和解锁(unLock)必须配对使用

 

2)使用NSRecursiveLock类实现锁 主要特点是允许相同线程 多次上锁,并通过一次 unlock来解锁


// 实例类person

Person *person = [[Person alloc] init];

// 创建锁对象

NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];


// 创建递归方法

static void (^testCode)(int);

testCode = ^(int value) {

    [theLock tryLock];

    if (value >0)

    {

        [person personA];

        [NSThread sleepForTimeInterval:1];

        testCode(value - 1);

    }

    [theLock unlock];

};


//线程A

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    testCode(5);

});


//线程B

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    [theLock lock];

    [person personB];

    [theLock unlock];

});


如果我们把NSRecursiveLock类换成NSLock类,那么程序就会死锁。因为在此例子中,递归方法会造成锁被多次锁定(Lock),所以自己也被阻塞了。而使用NSRecursiveLock类,则可以避免这个问题。

 

3)使用NSConditionLock(条件锁)类实现锁:

使用此方法可以创建一个指定开锁的条件,只有满足条件,才能开锁。


// 实例类person

Person *person = [[Person alloc] init];

// 创建条件锁

NSConditionLock *conditionLock = [[NSConditionLock alloc] init];


// 线程A

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    [conditionLock lock];

    [person personA];

    [NSThread sleepForTimeInterval:5];

    [conditionLock unlockWithCondition:10];

});


// 线程B

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    [conditionLock lockWhenCondition:10];

    [person personB];

    [conditionLock unlock];

});


线程A使用的是lock方法,因此会直接进行锁定,并且指定了只有满足10的情况下,才能成功解锁。

unlockWithCondition:方法,创建条件锁,参数传入整型lockWhenCondition:方法,则为解锁,也是传入一个整型的参数。

***NSConditionLock 借助 NSCondition 来实现,它的本质就是一个生产者-消费者模型。条件被满足可以理解为生产者提供了新的内容。NSConditionLock 的内部持有一个 NSCondition 对象,以及 _condition_value 属性,在初始化时就会对这个属性进行赋值:

// 简化版代码

- (id) initWithCondition: (NSInteger)value {

    if (nil != (self = [super init])) {

        _condition = [NSCondition new]

        _condition_value = value;

    }

    returnself;

}

它的 lockWhenCondition :

- (void) lockWhenCondition: (NSInteger)value {

    [_condition lock];

    while (value != _condition_value) {

        [_condition wait];

    }

}

对应的 unlockWhenCondition 

- (void) unlockWithCondition: (NSInteger)value {

    _condition_value = value;

    [_condition broadcast];

    [_condition unlock];

}





三、C语言

1)使用pthread_mutex_t实现锁

注意:必须在头文件导入:#import <pthread.h>


// 实例类person

Person *person = [[Person alloc] init];


// 创建锁对象

__block pthread_mutex_t mutex;

pthread_mutex_init(&mutex, NULL);


// 线程A

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    pthread_mutex_lock(&mutex);

    [person personA];

    [NSThread sleepForTimeInterval:5];

    pthread_mutex_unlock(&mutex);

});


// 线程B

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    pthread_mutex_lock(&mutex);

    [person personB];

    pthread_mutex_unlock(&mutex);

});


实现效果和上例的相一致

  

2)使用GCD实现(信号量)

GCD提供一种信号的机制,使用它我们可以创建(信号量和锁是有区别的,具体请自行百度)。


// 实例类person

Person *person = [[Person alloc] init];


// 创建并设置信量

dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);


// 线程A

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    [person personA];

    [NSThread sleepForTimeInterval:5];

    dispatch_semaphore_signal(semaphore);

});


// 线程B

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    [person personB];

    dispatch_semaphore_signal(semaphore);

});


效果也是和上例介绍的相一致。

我在这里解释一下代码。dispatch_semaphore_wait方法是把信号量加1dispatch_semaphore_signal是把信号量减1

我们把信号量当作是一个计数器,当计数器是一个非负整数时,所有通过它的线程都应该把这个整数减1。如果计数器大于0,那么则允许访问,并把计数器减1。如果为0,则访问被禁止,所有通过它的线程都处于等待的状态。

 

3)使用POSIX(条件锁)创建锁


// 实例类person

Person *person = [[Person alloc] init];


// 创建互斥锁

__block pthread_mutex_t mutex;

pthread_mutex_init(&mutex, NULL);

// 创建条件锁

__block pthread_cond_t cond;

pthread_cond_init(&cond, NULL);


// 线程A

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    pthread_mutex_lock(&mutex);

    pthread_cond_wait(&cond, &mutex);

    [person personA];

    pthread_mutex_unlock(&mutex);

});


// 线程B

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

    pthread_mutex_lock(&mutex);

    [person personB];

    [NSThread sleepForTimeInterval:5];

    pthread_cond_signal(&cond);

    pthread_mutex_unlock(&mutex);

});


效果:程序会首先调用线程B,在5秒后再调用线程A。因为在线程A中创建了等待条件锁,线程B有激活锁,只有当线程B执行完后会激活线程A

pthread_cond_wait方法为等待条件锁。

pthread_cond_signal方法为激动一个相同条件的条件锁。


参考:https://bestswifter.com/ios-lock/

http://www.cnblogs.com/GarveyCalvin/p/4212611.html#pthread_mutex_t


原创粉丝点击