避免误区!atomic的线程安全问题。

2018-09-13  本文已影响0人  我是繁星

背景

我们日常,在我们的印象中原子性是和线程安全划等号的,事实确实是这样的,不要被一些标题党误导😂,说他不是线程安全是相对于整个对象的。

概念

维基百科的解释:线程安全是指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程,使程序功能正确完成。其实意思就是多线程情况下程序的执行顺序要有单一性和正确性。

原子性:关于原子性可以看下这篇文章《关于原子性的理解》
概括一下原子性就是保证一个操作的完整性(不可被打断),在我们oc中就是保证setter和getter操作的完整性。

结论:

那我们的结论是这样的:
用atomic修饰后,这个属性的setter、getter方法是线程安全的,但是对于整个对象来说不一定是线程安全的。

原因:

1.为什么setter、getter方法是线程安全的?

因为在setter和getter赋值取值的时候添加了自旋锁,不懂看这《oc中的线程锁》

// getter
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
   // ...
   if (!atomic) return *slot;

   // Atomic retain release world
   spinlock_t& slotlock = PropertyLocks[slot];
   slotlock.lock();
   id value = objc_retain(*slot);
   slotlock.unlock();
   // ...
}

// setter
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
   // ...
   if (!atomic) {
       oldValue = *slot;
       *slot = newValue;
   } else {
       spinlock_t& slotlock = PropertyLocks[slot];
       slotlock.lock();
       oldValue = *slot;
       *slot = newValue;        
       slotlock.unlock();
   }
   // ...
}
2.为什么说atomic没办法保证整个对象的线程安全,这里主要看一下网上主流的答案?

1.对于NSArray类型 @property(atomic)NSArray *array我们用atomic修饰,数组的添加和删除并不是线程安全的,这是因为数组比较特殊,我们要分成两部分考虑,一部分是&array也就是这个数组本身,另一部分是他所指向的内存部分。atomic限制的只是&array部分,对于它指向的对象没有任何限制。
atomic表示,我TM也很冤啊!!!!

2.当线程A进行写操作,这时其他线程的读或者写操作会因为该操作而等待。当A线程的写操作结束后,B线程进行写操作,然后当A线程需要读操作时,却获得了在B线程中的值,这就破坏了线程安全,如果有线程C在A线程读操作前release了该属性,那么还会导致程序崩溃。所以仅仅使用atomic并不会使得线程安全,我们还要为线程添加lock来确保线程的安全。
个人觉得这个就有点杠精的意味了,atomic还要管到你方法外面去了?????不过面试人家问你还要这么答,要严谨!!

上一篇下一篇

猜你喜欢

热点阅读