Objective-C中不同方式实现锁(一)

点击打开链接

为什么需要使用锁,当然熟悉多线程的你,自然不会对它觉得陌生。

那你在代码中是否很好的使用了锁的机制呢?你又知道几种实现锁的方法呢?

今天一起来探讨一下Objective-C中几种不同方式实现的锁,在这之前我们先构建一个测试用的类,假想它是我们的一个共享资源,method1与method2是互斥的,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
@implementation TestObj
 
- ( void )method1
{
    NSLog ( @"%@" , NSStringFromSelector (_cmd));
}
 
- ( void )method2
{
    NSLog ( @"%@" , NSStringFromSelector (_cmd));    
}
 
@end

1.使用NSLock实现的锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//主线程中
TestObj *obj = [[TestObj alloc] init];
NSLock *lock = [[ NSLock alloc] init];
 
//线程1
dispatch_async ( dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     [lock lock];
     [obj method1];
     sleep (10);
     [lock unlock];
});
 
//线程2
dispatch_async ( dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     sleep (1); //以保证让线程2的代码后执行
     [lock lock];
     [obj method2];
     [lock unlock];
});

看到打印的结果了吗,你会看到线程1锁住之后,线程2会一直等待走到线程1将锁置为unlock后,才会执行method2方法。

NSLock是Cocoa提供给我们最基本的锁对象,这也是我们经常所使用的,除lock和unlock方法外,NSLock还提供了tryLock和lockBeforeDate:两个方法,前一个方法会尝试加锁,如果锁不可用(已经被锁住),刚并不会阻塞线程,并返回NO。lockBeforeDate:方法会在所指定Date之前尝试加锁,如果在指定时间之前都不能加锁,则返回NO。

2.使用synchronized关键字构建的锁

当然在Objective-C中你还可以用@synchronized指令快速的实现锁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//主线程中
TestObj *obj = [[TestObj alloc] init];
 
//线程1
dispatch_async ( dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     @synchronized (obj){
         [obj method1];
         sleep (10);
     }
});
 
//线程2
dispatch_async ( dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     sleep (1);
     @synchronized (obj){
         [obj method2];
     }
});

@synchronized指令使用的obj为该锁的唯一标识,只有当标识相同时,才为满足互斥,如果线程2中的@synchronized(obj)改为@synchronized(other),刚线程2就不会被阻塞,@synchronized指令实现锁的优点就是我们不需要在代码中显式的创建锁对象,便可以实现锁的机制,但作为一种预防措施,@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。

3.使用C语言的pthread_mutex_t实现的锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//主线程中
TestObj *obj = [[TestObj alloc] init];
 
__block pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL );
 
//线程1
dispatch_async ( dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     pthread_mutex_lock(&mutex);
     [obj method1];
     sleep (5);
     pthread_mutex_unlock(&mutex);
});
 
//线程2
dispatch_async ( dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     sleep (1);
     pthread_mutex_lock(&mutex);
     [obj method2];
     pthread_mutex_unlock(&mutex);
});

pthread_mutex_t定义在pthread.h,所以记得#include <pthread.h>
4.使用GCD来实现的”锁”
以上代码构建多线程我们就已经用到了GCD的dispatch_async方法,其实在GCD中也已经提供了一种信号机制,使用它我们也可以来构建一把”锁”(从本质意义上讲,信号量与锁是有区别,具体差异参加信号量与互斥锁之间的区别):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//主线程中
TestObj *obj = [[TestObj alloc] init];
dispatch_semaphore_t semaphore = dispatch_semaphore_create (1);
 
//线程1
dispatch_async ( dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     dispatch_semaphore_wait (semaphore, DISPATCH_TIME_FOREVER);
     [obj method1];
     sleep (10);
     dispatch_semaphore_signal (semaphore);
});
 
//线程2
dispatch_async ( dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     sleep (1);
     dispatch_semaphore_wait (semaphore, DISPATCH_TIME_FOREVER);
     [obj method2];
     dispatch_semaphore_signal (semaphore);
});

至于代码产生的效果当然和上一例是一模一样的,关于信号机制,熟悉C编程的你肯定也不会陌生的,关于GCD中更多关于dispatch_semaphore_t的信息,可以跳转到本博客的这一往篇文章:GCD介绍(三): Dispatch Sources

好了,以上就是我所列举了几种方式来实现锁,当然锁大多数情况下也是配合多线程一起使用的,关于多线程编程,我这儿就不赘述了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值