锁是线程编程同步工具的基础。锁可以让你很容易保护代码中一大块区域以便你可以确保代码的正确性。
1 使用POSIX互斥锁
POSIX互斥锁在很多程序里面很容易使用。为了新建一个互斥锁,你声明并初始化一个pthread_mutex_t的结构。为了锁住和解锁一个互斥锁,你可以使用pthread_mutex_lock和pthread_mutex_unlock函数。列表4-2显式了要初始化并使用一个POSIX线程的互斥锁的基础代码。当你用完一个锁之后,只要简单的调用pthread_mutex_destroy来释放该锁的数据结构。
Listing 4-2
Using a mutex lock pthread_mutex_t mutex;
void MyInitFunction()
{
pthread_mutex_init(&mutex, NULL);
}
void MyLockingFunction()
{
pthread_mutex_lock(&mutex);
// Do work. pthread_mutex_unlock(&mutex);
}
注意:上面的代码只是简单的显式了使用一个POSIX线程互斥锁的步骤。你自己的代码应该检查这些函数返回的错误码,并适当的处理它们。
4.6.2 使用NSLock类
在Cocoa程序中NSLock中实现了一个简单的互斥锁。所有锁(包括NSLock)的接口实际上都是通过NSLocking协议定义的,它定义了lock和unlock方法。你使用这些方法来获取和释放该锁。
除了标准的锁行为,NSLock类还增加了tryLock和lockBeforeDate:方法。方法tryLock试图获取一个锁,但是如果锁不可用的时候,它不会阻塞线程。相反,它只是返回NO。而lockBeforeDate:方法试图获取一个锁,但是如果锁没有在规定的时间内被获得,它会让线程从阻塞状态变为非阻塞状态(或者返回NO)。
下面的例子显式了你可以是NSLock对象来协助更新一个可视化显式,它的数据结构被多个线程计算。如果线程没有立即获的锁,它只是简单的继续计算直到它可以获得锁再更新显式。
BOOL moreToDo = YES;
NSLock *theLock = [[NSLock alloc] init];
...
while (moreToDo) {
if ([theLock tryLock]) {
[theLock unlock];
}
}
4.6.3 使用@synchronized指令
@synchronized指令是在Objective-C代码中创建一个互斥锁非常方便的方法。@synchronized指令做和其他互斥锁一样的工作(它防止不同的线程在同一时间获取同一个锁)。然而在这种情况下,你不需要直接创建一个互斥锁或锁对象。相反,你只需要简单的使用Objective-C对象作为锁的令牌,如下面例子所示:
- (void)myMethod:(id)anObj
{
@synchronized(anObj)
{
// Everything between the braces is protected by the @synchronized directive.
}
}
创建给@synchronized指令的对象是一个用来区别保护块的唯一标示符。如果你在两个不同的线程里面执行上述方法,每次在一个线程传递了一个不同的对象给anObj参数,那么每次都将会拥有它的锁,并持续处理,中间不被其他线程阻塞。然而,如果你传递的是同一个对象,那么多个线程中的一个线程会首先获得该锁,而其
他线程将会被阻塞直到第一个线程完成它的临界区。
作为一种预防措施,@synchronized块隐式的添加一个异常处理例程来保护代码。该处理例程会在异常抛出的时候自动的释放互斥锁。这意味着为了使用@synchronized指令,你必须在你的代码中启用异常处理。了如果你不想让隐式的异常处理例程带来额外的开销,你应该考虑使用锁的类。
4.6.4 使用其他Cocoa锁
以下个部分描述了使用Cocoa其他类型的锁。
·使用NSRecursiveLock对象
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对象定义了一个互斥锁,可以使用特定值来锁住和解锁。不要把该类型的锁和条件(参见“条件”部分)混淆了。它的行为和条件有点类似,但是它们的实现非常不同。
通常,当多线程需要以特定的顺序来执行任务的时候,你可以使用一个NSConditionLock对象,比如当一个线程生产数据,而另外一个线程消费数据。生产者执行时,消费者使用由你程序指定的条件来获取锁(条件本身是一个你定义的整形值)。当生产者完成时,它会解锁该锁并设置锁的条件为合适的整形值来唤醒消费者线程,之后消费线程继续处理数据。
NSConditionLock的锁住和解锁方法可以任意组合使用。比如,你可以使用unlockWithCondition:和lock消息,或使用lockWhenCondition:和unlock消息。当然,后面的组合可以解锁一个锁但是可能没有释放任何等待某特定条件值的线程。
下面的例子显示了生产者-消费者问题如何使用条件锁来处理。想象一个应用程序包含一个数据的队列。一个生产者线程把数据添加到队列,而消费者线程从队列中取出数据。生产者不需要等待特定的条件,但是它必须等待锁可用以便它可以安全的把数据添加到队列。
id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA];
while(true) {
[condLock lock];
[condLock unlockWithCondition:HAS_DATA];
}
因为初始化条件锁的值为NO_DATA,生产者线程在初始化的时候可以毫无问题的获取该锁。它会添加队列数据,并把条件设置为HAS_DATA。在随后的迭代中,生产者线程可以把到达的数据添加到队列,无论队列是否为空或依然有数据。唯一让它进入阻塞的情况是当一个消费者线程充队列取出数据的时候。
因为消费者线程必须要有数据来处理,它会使用一个特定的条件来等待队列。当生产者把数据放入队列时,消费者线程被唤醒并获取它的锁。它可以从队列中取出数据,并更新队列的状态。下列代码显示了消费者线程处理循环的基本结构。
while (true) {
[condLock lockWhenCondition:HAS_DATA];
[condLock unlockWithCondition:(isEmpty ? NO_DATA : HAS_DATA)];
// Process the data locally.
}
·使用NSDistributedLock对象
NSDistributedLock类可以被多台主机上的多个应用程序使用来限制对某些共享资源的访问,比如一个文件。锁本身是一个高效的互斥锁,它使用文件系统项目来实现,比如一个文件或目录。对于一个可用的NSDistributedLock对象,锁必须由所有使用它的程序写入。这通常意味着把它放在文件系统,该文件系统可以被所有运行在计算机上面的应用程序访问。
不像其他类型的锁,NSDistributedLock并没有实现NSLocking协议,所有它没有lock方法。一个lock方法将会阻塞线程的执行,并要求系统以预定的速度轮询锁。以其在你的代码中实现这种约束,NSDistributedLock提供了一个tryLock方法,并让你决定是否轮询。
因为它使用文件系统来实现,一个NSDistributedLock对象不会被释放除非它的拥有者显式的释放它。如果你的程序在用户一个分布锁的时候崩溃了,其他客户端无法访问该受保护的资源。在这种情况下,你可以使用breadLock方法来打破现存的锁以便你可以获取它。但是通常应该避免打破锁,除非你确定拥有进程已经死亡并不可能再释放该锁。
和其他类型的锁一样,当你使用NSDistributedLock对象时,你可以通过调用unlock方法来释放它。
来源: http://blog.sina.com.cn/s/blog_72819b170101590n.html
相关推荐
iOS-高仿支付宝手势解锁(九宫格)_Objective-C_下载.zip
用户手势锁定和解锁视图_Objective-C_Ruby_下载.zip
QQ和TouchID等手势锁屏,高仿QQ手势锁屏,手指解锁_Objective-C_C++_下载.zip
与Objective-C指令类似,Synchronized获取一个互斥锁,运行一些代码,并在代码完成或引发异常时释放该锁。链接框架可通过获得同步。 要安装它,只需将以下行添加到您的Podfile中: pod "Synchronized", "~> 4.0"您...
该库已创建,可以在使用代码中使用。 尽管这不是必需的。 如何安装? 只需将这四个文件包含到您的iOS或Mac项目中: TrReadWriteLock.h TrReadWriteLock.m NSObject+TrReadWriteLockAdditions.h NSObject+...
Infer是一种静态分析工具-如果您提供Infer一些Java或C / C ++ / Objective-C代码,则会生成一系列潜在错误。 任何人都可以使用Infer在将严重错误发布给用户之前拦截它们,并帮助防止崩溃或性能下降。 推断检查...
YLSwipeLockView, 在 Objective C 中,双击 swipe password以解锁已经编写的应用程序 YLSwipeLockViewswipe密码view以解锁用 objective-c 编写的应用程序 要求YLSwipeLockView在 iOS 6.0和更高版本上工作,并且与 ...
1、开锁: 下载程序后,直接按六次S7(即代表数字1),8位LED...推荐初级演示步骤:输入原始密码000000---按下更改密码按键S16---按0到9设置密码---按S17 确认密码更改---按S18关闭密码锁---输入新的密码打开密码锁
下面是一个使用锁的例子: - (Person*)personAtIndex:( NSUInteger )index { [_lock lock ]; defer (^() { [_lock unlock ]; }); return [_array objectAtIndex: index ];} 锁定在方法开始时获得,解锁被推迟到方法...
objective-c实现的ios手势解锁代码,比较完整,直接加入工程可用。
• 具有低内存占用的本机C/Objective-C/Java 代码。 • 适用于大量日志(最多 65536 个条目)。 • 使用本机平台UI 构建(不依赖Unity GUI)。 • 与分辨率无关(在高分辨率/视网膜显示屏上看起来很棒)。 • 不...
-手势解锁,模仿支付宝解锁页面如图所示:
多线程在各种编程语言中都是难点,很多语言中实现起来很麻烦,objective-c虽然源于c,但其多线程编程却相当简单,可以与java相媲美。这篇文章主要从线程创建与启动、线程的同步与锁、线程的交互、线程池等等四个方面...
iOS图案解锁屏 PatternLock ,PatternLock 在 iOS 上实现了图案解锁屏的功能,使用方法: - (id)initWit...
一个朋友可以发送他/她的位置的消息或图像,其他人一旦进入大楼就可以收到消息并轻松找到对方技术栈后端:Ruby on Rails 网络:JavaScript、谷歌地图 API iOS:Objective-C、AFNetworking、地理围栏截图![ios0]...
iOS 滑动解锁 MBSliderView ,MBSliderView 是一个 iOS 控件实现了滑动解锁的功能,使用方便而且可轻松定制。
密码解锁控件 KKPasscodeLock ,KKPasscodeLock 实现了类似 iPhone 上的密码解锁屏幕的控件。 ...
Gesture-unlock模仿支付宝手势解锁的一个Demo
## 进入你weex项目中的ios目录,执行git clone git clone https://github.com/shawn-tangsc/WeexPlugin-HMGesUnlock 其次,修改你ios项目的Podfile文件,加入 pod 'WeexHMGesUnlock', :path=>'./WeexPlugin-...
智能门锁iOS应用适用于智能门锁项目的iOS应用