iOS 中关于@synchronized的一点思考

参考 :

https://www.cnblogs.com/jukaiit/p/5570056.html

https://www.cnblogs.com/CoderAlex/p/5257339.html

http://www.cocoachina.com/ios/20161205/18279.html

http://www.jianshu.com/p/1e59f0970bf5

首先我们知道@synchronized 的作用是创建一个互斥锁,保证此时没有其它线程对锁对象进行修改。这个是objective-c的一个锁定令牌,防止锁对象在同一时间内被其它线程访问,起到线程的保护作用。

指令@synchronized()通过对一段代码的使用进行加锁。其他试图执行该段代码的线程都会被阻塞,直到加锁线程退出执行该段被保护的代码段

相关术语:

线程同步:多天线程在同一条线上执行(按顺序的执行任务)

互斥锁就是使用了线程同步技术

下面看互斥锁使用格式

 @synchronized (锁对象) {
         加锁代码
        }

锁定一份代码只能用一把锁,多把锁是无效的。

优点:防止多线程操作时资源竞争导致的数据安全问题

缺点:需要消耗大量的CPU资源


互斥锁的使用前提是:多条线程使用同一份资源。


查看该段的汇编代码可知主要使用了两个函数

 _objc_sync_enter
  _objc_sync_exit
在Objective-C 中查看源码
int objc_sync_enter(id obj)
{
    int result = OBJC_SYNC_SUCCESS;

    if (obj) {
        SyncData* data = id2data(obj, ACQUIRE);
        assert(data);
        data->mutex.lock();
    } else {
        // @synchronized(nil) does nothing
        if (DebugNilSync) {
            _objc_inform("NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug");
        }
        objc_sync_nil();
    }

    return result;
}


// End synchronizing on 'obj'. 
// Returns OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR
int objc_sync_exit(id obj)
{
    int result = OBJC_SYNC_SUCCESS;
    
    if (obj) {
        SyncData* data = id2data(obj, RELEASE); 
        if (!data) {
            result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
        } else {
            bool okay = data->mutex.tryUnlock();
            if (!okay) {
                result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
            }
        }
    } else {
        // @synchronized(nil) does nothing
    }
	

    return result;
}


查看SyncData

typedef struct SyncData {
    struct SyncData* nextData;
    DisguisedPtr<objc_object> object;
    int32_t threadCount;  // number of THREADS using this block
    recursive_mutex_t mutex;
} SyncData;

可见在SyncData 维护了一个递归锁,所以如下代码就不会死锁。

@synchronized (obj) {
    NSLog(@"13qw");
    @synchronized (obj) {
        NSLog(@"2asda");
    }
}
 

但是并不意味着synchronized不会死锁,类似下面的代码还是会导致死锁的

@synchronized (self) {
    [_sharedLock lock];
    NSLog(@"code in class A");
    [_sharedLock unlock];
}

正确使用@synchronized还需要注意粒度控制
 
@synchronized (token) {
    [arrA addObject:obj];
}
@synchronized (token) {
    [arrB addObject:obj];
}

使用同一个token来同步arrA和arrB的访问,虽然arrA和arrB之间没有任何联系。传入self的就更不对了。

应该是不同的数据使用不同的锁,尽量将粒度控制在最细的程度。上述代码应该是:

@synchronized (tokenA) {
    [arrA addObject:obj];
}
@synchronized (tokenB) {
    [arrB addObject:obj];
}

@synchronized(nil)不起任何作用,所以传参时还是需要做好判断


注意内部的函数调用

@synchronized (tokenA) {
     [arrA addObject:obj];
     [self doSomething:arrA];
}

在  doSomething:中可能有更多的函数调用,这样就会导致@synchronized更慢,所以建议@synchronized内加锁的代码还是尽量简单的好,
如果无法避免,还是要做好维护工作






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值