直播系统开发,iOS端不得不关注的互斥锁

直播系统开发,iOS端不得不关注的互斥锁

1.pthread_mutex

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);

 

2.@synchronized

@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);
}

 

3.NSLock

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];
        });
    }
}

 

4.NSRecursiveLock

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中有用到

5.NSCondition

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端不得不关注的互斥锁, 更多内容欢迎关注之后的文章

posted @ 2025-04-19 10:11  云豹科技-苏凌霄  阅读(26)  评论(0)    收藏  举报