首页 存档 技术 查看内容

iOS 中的各种锁

2018-3-30 13:00 |来自: 互联网 282 0

摘要: 来源:XcodeMen 链接:http://www.jianshu.com/p/6c8bf19eb10d 在日常开发过程中,为了提升程序运行效率,以及用户体验,我们经常使用多线程。在使用多线程的过程中,难免会遇到资源竞争问题。我们采用锁的机制来确 ...

来源:XcodeMen

链接:http://www.jianshu.com/p/6c8bf19eb10d


在日常开发过程中,为了提升程序运行效率,以及用户体验,我们经常使用多线程。在使用多线程的过程中,难免会遇到资源竞争问题。我们采用锁的机制来确保线程安全。


线程安全


当一个线程访问数据的时候,其他的线程不能对其进行访问,直到该线程访问完毕。即,同一时刻,对同一个数据操作的线程只有一个。只有确保了这样,才能使数据不会被其他线程污染。而线程不安全,则是在同一时刻可以有多个线程对该数据进行访问,从而得不到预期的结果。


比如写文件和读文件,当一个线程在写文件的时候,理论上来说,如果这个时候另一个线程来直接读取的话,那么得到将是不可预期的结果。


为了线程安全,我们可以使用锁的机制来确保,同一时刻只有同一个线程来对同一个数据源进行访问。在开发过程中我们通常使用以下几种锁。


  1. NSLock

  2. NSRecursiveLock

  3. NSCondition

  4. NSConditionLock

  5. pthread_mutex

  6. pthread_rwlock

  7. POSIX Conditions

  8. OSSpinLock

  9. os_unfair_lock

  10. dispatch_semaphore

  11. @synchronized


信号量


在多线程环境下用来确保代码不会被并发调用。在进入一段代码前,必须获得一个信号量,在结束代码前,必须释放该信号量,其他想要想要执行该代码的线程必须等待直到前者释放了该信号量。


以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。

在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。


互斥锁


一种用来防止多个线程同一时刻对共享资源进行访问的信号量,它的原子性确保了如果一个线程锁定了一个互斥量,将没有其他线程在同一时间可以锁定这个互斥量。它的唯一性确保了只有它解锁了这个互斥量,其他线程才可以对其进行锁定。当一个线程锁定一个资源的时候,其他对该资源进行访问的线程将会被挂起,直到该线程解锁了互斥量,其他线程才会被唤醒,进一步才能锁定该资源进行操作。


NSLock


NSLock实现了最基本的互斥锁,遵循了 NSLocking 协议,通过 lock 和 unlock 来进行锁定和解锁。其使用也非常简单


-(void)doSomething{

[self.locklock];

//TODO: do your stuff

[self.lockunlock];

}


由于是互斥锁,当一个线程进行访问的时候,该线程获得锁,其他线程进行访问的时候,将被操作系统挂起,直到该线程释放锁,其他线程才能对其进行访问,从而却确保了线程安全。但是如果连续锁定两次,则会造成死锁问题。那如果想在递归中使用锁,那要怎么办呢,这就用到了 NSRecursiveLock 递归锁。


NSRecursiveLock


递归锁,顾名思义,可以被一个线程多次获得,而不会引起死锁。它记录了成功获得锁的次数,每一次成功的获得锁,必须有一个配套的释放锁和其对应,这样才不会引起死锁。只有当所有的锁被释放之后,其他线程才可以获得锁


NSRecursiveLock *theLock=[[NSRecursiveLockalloc]init];

voidMyRecursiveFunction(intvalue)

{

[theLocklock];

if(value!=0)

{

--value;

MyRecursiveFunction(value);

}

[theLockunlock];

}

MyRecursiveFunction(5);


NSCondition


NSCondition 是一种特殊类型的锁,通过它可以实现不同线程的调度。一个线程被某一个条件所阻塞,直到另一个线程满足该条件从而发送信号给该线程使得该线程可以正确的执行。比如说,你可以开启一个线程下载图片,一个线程处理图片。这样的话,需要处理图片的线程由于没有图片会阻塞,当下载线程下载完成之后,则满足了需要处理图片的线程的需求,这样可以给定一个信号,让处理图片的线程恢复运行。


声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除


路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部