objective-c - 为什么在多个线程内修改NSMutableSet时崩溃,但是在同一线程内修改自定义对象Person却不会崩溃?

标签 objective-c multithreading thread-safety pthreads grand-central-dispatch

下面是代码。在街区里,我尝试了3种情况。一次只休息一个案例。

set = [[NSMutableSet alloc] init];
Person* p = [[Person alloc] init];

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
for (int index = 0; index < 100; index++) {
    dispatch_async(queue, ^{

            //Case 1: adding constant value each time
            //[self->set addObject:@"0"];

            //Case 2: adding new value on each call.
            [self->set addObject:[NSNumber numberWithInt:index]];

            //Case 3: Modifying custom object
             // p.firstname = [NSString stringWithFormat:@"%d", index];
    });

}

我知道如果我在块内放入锁/@ syncronize可以正常工作。

问题1 :为什么即使我尝试使用0到100000的索引范围,情况一仍然运行没有问题。可变集不是线程安全的,因此它一定会崩溃。那么为什么它不同步就可以工作呢?

问题2 :由于情况1每次都运行良好,因此情况2也应运行良好,因为正在修改同一集合。但是每次运行都会崩溃。

问题3 :情况3不会崩溃,即使我每次都以新情况输入新值,以防万一。

注意:所有属性均为非原子性。

案例2崩溃日志:
**malloc: *** **error for object 0x6000028e9260: pointer being freed was not allocated****

最佳答案

首先,我们要弄清楚,这些都不是线程安全的。如果您确实要从多个线程进行同步,则需要进行同步。

其次,您还应该毫不犹豫地从无法产生特定崩溃的问题中得出结论。众所周知,它们很难表现出来。另外,您正在测试的行为范围非常狭窄,从不测试读取是否成功,返回的对象在内部是否一致等。

对于将同一对象重复添加到集合中,这不是一个很好的测试,因为随后的添加无疑会确定该对象已经在集合中,因此实际上没有发生突变。

在您的自定义对象示例中,您要做的就是更改单个指针,但从不使用它。加上某些硬件功能将使无论如何都很难表现出任何问题。这并不意味着您不需要同步,而只是要表明问题非常困难。

此外,自定义对象(如“人”)的同步通常需要在更高的抽象级别上进行(例如,如果更改人的全名,那么同时读取实际上应该等待所有三个属性(名,中间名和姓氏)完成,否则您可能会陷入不确定状态)。

最重要的是,如果要从多个线程访问它们,则应该将您的交互与可变集和可变人对象进行同步。

我建议您研究一下线程 sanitizer (TSAN,送给它的 friend )。因此,在Xcode中,转到“编辑器”»“方案”»“编辑方案...”,然后打开线程清理器:

enter image description here

这将帮助您识别来自多个线程的不安全访问。有关更多信息,请参见Thread Sanitizer and Static Analyzer视频。

但是正如苹果在上述视频中建议的那样,“没有“良性”竞赛。”

关于objective-c - 为什么在多个线程内修改NSMutableSet时崩溃,但是在同一线程内修改自定义对象Person却不会崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55088872/

相关文章:

ios - Google Place Request_Denied 恐怖

java - 从 Cocoa 应用程序调用 Java 程序

Java SWT 和无效的线程访问

java - Notify 和 NotifyAll 仅影响处于阻塞状态的线程

ios - 分享有关 linkedin 不支持新 v2 Api 的文章

ios - 如何在 iOS 上使用 GSEvent 模拟触摸移动事件?

Java icmp4j 多线程 ping 不那么多线程

multithreading - 使用 web.py 强制单线程请求处理

java - ThreadLocal 和列表不起作用

c - C 中中断驱动环境中主线程和从线程之间共享数据