直播系统开发,iOS端不得不关注的互斥锁
直播系统开发,iOS端不得不关注的互斥锁
pthread_mutex就是互斥锁本身——当锁被占用,而其他线程申请锁时,不是使用忙等,而是阻塞线程并睡眠
使用如下:
// 导入头文件 #import <pthread.h> // 全局声明互斥锁 pthread_mutex_t _lock; // 初始化互斥锁 pthread_mutex_init(&_lock, NULL); // 加锁 pthread_mutex_lock(&_lock); // 这里做需要线程安全操作 // ... // 解锁 pthread_mutex_unlock(&_lock); // 释放锁 pthread_mutex_destroy(&_lock);
@synchronized可能是日常开发中用的比较多的一种互斥锁,因为它的使用比较简单,但并不是在任意场景下都能使用@synchronized,且它的性能较低
@synchronized (obj) {}
接下来就通过源码探索来看一下@synchronized在使用中的注意事项
1、通过汇编能发现@synchronized就是实现了objc_sync_enter和 objc_sync_exit两个方法
2、通过符号断点能知道这两个方法都是在objc源码中的
3、通过clang也能得到一些信息:
int main(int argc, char * argv[]) { NSString * appDelegateClassName; /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; appDelegateClassName = NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))); { id _rethrow = 0; id _sync_obj = (id)appDelegateClassName; objc_sync_enter(_sync_obj); try { struct _SYNC_EXIT { _SYNC_EXIT(id arg) : sync_exit(arg) {} ~_SYNC_EXIT() { objc_sync_exit(sync_exit); } id sync_exit; } _sync_exit(_sync_obj); } catch (id e) {_rethrow = e;} { struct _FIN { _FIN(id reth) : rethrow(reth) {} ~_FIN() { if (rethrow) objc_exception_throw(rethrow); } id rethrow; }_fin_force_rethow(_rethrow); } } } return UIApplicationMain(argc, argv, __null, appDelegateClassName); }
NSLock是对互斥锁的简单封装,使用如下:
- (void)test { self.testArray = [NSMutableArray array]; NSLock *lock = [[NSLock alloc] init]; for (int i = 0; i < 200000; i++) { dispatch_async(dispatch_get_global_queue(0, 0), ^{ [lock lock]; self.testArray = [NSMutableArray array]; [lock unlock]; }); } }
NSRecursiveLock使用和NSLock类似,如下代码就能解决上个问题
- (void)test { NSRecursiveLock *lock = [[NSRecursiveLock alloc] init]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ static void (^block)(int); block = ^(int value) { [lock lock]; if (value > 0) { NSLog(@"value——%d", value); block(value - 1); } [lock unlock]; }; block(10); }); }
NSRecursiveLock在YYKit中YYWebImageOperation.m中有用到
NSCondition是一个条件锁,可能平时用的不多,但与信号量相似:线程1需要等到条件1满足才会往下走,否则就会堵塞等待,直至条件满足
同样的能在Swift源码中找到关于NSCondition部分
open class NSCondition: NSObject, NSLocking { internal var mutex = _MutexPointer.allocate(capacity: 1) internal var cond = _ConditionVariablePointer.allocate(capacity: 1) public override init() { pthread_mutex_init(mutex, nil) pthread_cond_init(cond, nil) } deinit { pthread_mutex_destroy(mutex) pthread_cond_destroy(cond) } open func lock() { pthread_mutex_lock(mutex) } open func unlock() { pthread_mutex_unlock(mutex) } open func wait() { pthread_cond_wait(cond, mutex) } open func wait(until limit: Date) -> Bool { guard var timeout = timeSpecFrom(date: limit) else { return false } return pthread_cond_timedwait(cond, mutex, &timeout) == 0 } open func signal() { pthread_cond_signal(cond) } open func broadcast() { pthread_cond_broadcast(cond) // wait signal } open var name: String? }
从上述精简后的代码可以得出以下几点:
1、NSCondition是对mutex和cond的一种封装(cond就是用于访问和操作特定类型数据的指针)
2、wait操作会阻塞线程,使其进入休眠状态,直至超时
3、signal操作是唤醒一个正在休眠等待的线程
4、broadcast会唤醒所有正在等待的线程
6.NSConditionLock
顾名思义,就是NSCondition + Lock
那么和NSCondition的区别在于哪里呢?接下来看一下NSConditionLock源码
open class NSConditionLock : NSObject, NSLocking { internal var _cond = NSCondition() internal var _value: Int internal var _thread: _swift_CFThreadRef? public convenience override init() { self.init(condition: 0) } public init(condition: Int) { _value = condition } open func lock() { let _ = lock(before: Date.distantFuture) } open func unlock() { _cond.lock() _thread = nil _cond.broadcast() _cond.unlock() } open var condition: Int { return _value } open func lock(whenCondition condition: Int) { let _ = lock(whenCondition: condition, before: Date.distantFuture) } open func `try`() -> Bool { return lock(before: Date.distantPast) } open func tryLock(whenCondition condition: Int) -> Bool { return lock(whenCondition: condition, before: Date.distantPast) } open func unlock(withCondition condition: Int) { _cond.lock() _thread = nil _value = condition _cond.broadcast() _cond.unlock() } open func lock(before limit: Date) -> Bool { _cond.lock() while _thread != nil { if !_cond.wait(until: limit) { _cond.unlock() return false } } _thread = pthread_self() _cond.unlock() return true } open func lock(whenCondition condition: Int, before limit: Date) -> Bool { _cond.lock() while _thread != nil || _value != condition { if !_cond.wait(until: limit) { _cond.unlock() return false } } _thread = pthread_self() _cond.unlock() return true } open var name: String? }
从上述代码可以得出以下几点:
1、NSConditionLock是NSCondition加线程数的封装
2、NSConditionLock可以设置锁条件,而NSCondition只是无脑的通知信号
以上就是直播系统开发,iOS端不得不关注的互斥锁, 更多内容欢迎关注之后的文章