您的位置:首页 > 移动开发 > IOS开发

iOS 中关于@synchronized的一点思考

2017-11-24 18:34 267 查看
参考 :

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 (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)不起任何作用,所以传参时还是需要做好判断

注意内部的函数调用

在 doSomething:中可能有更多的函数调用,这样就会导致@synchronized更慢,所以建议@synchronized内加锁的代码还是尽量简单的好,
如果无法避免,还是要做好维护工作
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: