线程安全
多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染这种情况,
意思就是说在多线程操作共享数据不会出现想不到的结果就是线程安全的,否则,是线程不安全的。
锁的作用
防止在多线程的情况下对共享资源脏读和脏写
2.自旋锁和互斥锁
共同点:
都能保证同一时刻只有一个线程操作锁住的代码,都能保证线程安全。
不同点:
互斥锁(mutex),当一个线程的任务没有执行完的时候(被锁住)那么下一个线程就进入睡眠状态等待任务执行完成,当上个任务执行完成后,下一个线程会自动唤醒后执行任务。
自旋锁(spin lock):当上一个线程的任务没有执行完时,那么下个线程会一直等待,当上一个线程的任务执行完成后,下一个线程会立即执行。由于自旋锁不会引起调用者睡眠,所以自旋锁效率高于互斥锁。
自旋锁会一直占用CPU,也可能造成死锁。
自旋锁问题:不同优先级线程调度算法会有优先级反转问题,比如低优先级获锁访问资源,高优先级尝试访问时会等待,这时低优先级又没法争过高优先级导致任务无法完成lock释放不了。
新版 iOS 中,系统维护了 5 个不同的线程优先级/QoS: background,utility,default,user-initiated,user-interactive。高优先级线程始终会在低优先级线程前执行,一个线程不会受到比它更低优先级线程的干扰。这种线程调度算法会产生潜在的优先级反转问题,从而破坏了 spin lock。
所谓优先级翻转问题(Priority Inversion)即当一个高优先级任务通过信号量机制访问共享资源时,该信号量已被一低优先级任务占有,而这个低优先级任务在访问共享资源时可能又被其它一些中等优先级任务抢先,因此造成高优先级任务被许多具有较低优先级任务阻塞,实时性难以得到保证。
任务 A: 优先级高,要使用资源S,使用完后程序结束
任务 B: 优先级中,不使用共享资源S
任务 C:优先级低,要使用资源S,使用完后程序结束
例如:有优先级为A、B和C三个任务,优先级A>B>C,任务A,B处于挂起状态,等待某一事件发生,任务C正在运行,此时任务C开始使用某一共享资源S。在使用中,任务A等待事件到来,任务A转为就绪态,因为它比任务C优先级高,所以立即执行。当任务A要使用共享资源S时,由于其正在被任务C使用,因此任务A被挂起,任务C开始运行。如果此时任务B等待事件到来,则任务B转为就绪态。由于任务B优先级比任务C高,因此任务B开始运行,直到其运行完毕,任务C才开始运行。直到任务C释放共享资源S后,任务A才得以执行。在这种情况下,优先级发生了翻转,任务B先于任务A运行
解决优先级翻转问题有优先级天花板和优先级继承两种办法。
1.1 优先级天花板(Priority Ceiling)
优先级天花板是当任务申请某资源时, 把该任务的优先级提升到可访问这个资源的所有任务中的最高优先级, 这个优先级称为该资源的优先级天花板。这种方法简单易行, 不必进行复杂的判断, 不管任务是否阻塞了高优先级任务的运行, 只要任务访问共享资源都会提升任务的优先级。
1.2 优先级继承(Priority Inheritance)
优先级继承是当任务A 申请共享资源S 时, 如果S正在被任务C 使用,通过比较任务C 与自身的优先级,如发现任务C 的优先级小于自身的优先级, 则将任务C的优先级提升到自身的优先级, 任务C 释放资源S 后,再恢复任务C 的原优先级。这种方法只在占有资源的低优先级任务阻塞了高优先级任务时才动态的改变任务的优先级,如果过程较复杂, 则需要进行判断。
除非开发者能保证访问锁的线程全部都处于同一优先级,否则 iOS 系统中所有类型的自旋锁都不能再使用了。
如何实现一个线程安全的NSMutabeArray,以保证多个线程对数组操作(遍历,插入,删除)的安全?
在实际开发中,有多个类可能在不同线程中同时操作数组,除了插入删除外,
还有遍历,
还有遍历,
还有遍历,
并且线程A在遍历时,线程B可能直接把数组给清空了,直接crash。
目前想到的解决方案是实现一个diapatch_queue,重载插入删除方法,使其在这个执行队列中进行,但是,遍历怎么办?
某个线程在遍历数组时,往往要直接得到一个结果然后继续执行,看起来并不能放到自定的执行队列中,这该如何解决,求大神给个解决思路,谢过了。
网友评论