@synchronized 在 MRC 中不起作用,我的应用程序在多线程中崩溃

Posted

技术标签:

【中文标题】@synchronized 在 MRC 中不起作用,我的应用程序在多线程中崩溃【英文标题】:@synchronized not working in MRC,my app crash in multithreaded 【发布时间】:2014-09-16 02:19:13 【问题描述】:
//person.h
@interface Person : NSObject

@property(retain, nonatomic) NSString *indexStr;

- (instancetype)initWithIndex:(int)index;

- (void)print;

@end

//person.m
@implementation Person

- (instancetype)initWithIndex:(int)index

    if (self = [super init]) 
        _indexStr = [NSString stringWithFormat:@"%d",index];
        NSLog(@"person init index:%d",index);
    
    return self;


- (void)dealloc

    self.indexStr = nil;
    NSLog(@"person dealloc index:%@",self.indexStr);
    [super dealloc];


@end    

//vc.h
@property (retain, nonatomic) Person *person;

//vc.m
- (void)viewDidLoad 
    [super viewDidLoad];

    _person = [[Person alloc] initWithIndex:-1];

    for (int i = 0; i < 100000; i++) 
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
            [self actionWrite:@(i)];
        );
    

    //    [NSThread detachNewThreadSelector:@selector(actionRead) toTarget:self withObject:nil];


- (void)actionWrite:(NSNumber *)num

    @synchronized(self) 
        self.person = [[[Person alloc] initWithIndex:[num intValue]] autorelease];
    

代码在 MRC 中。

它会在“actionWrith:”方法处崩溃。日志是:

2014-09-16 10:11:26.452 testThreadNoARC[1777:149948] person init index:357
2014-09-16 10:11:26.452 testThreadNoARC[1777:149961] person init index:358
2014-09-16 10:11:26.452 testThreadNoARC[1777:149947] person init index:359
2014-09-16 10:11:26.452 testThreadNoARC[1777:149937] person init index:360
2014-09-16 10:11:26.452 testThreadNoARC[1777:149944] person init index:361
2014-09-16 10:11:26.452 testThreadNoARC[1777:149950] person init index:362
2014-09-16 10:11:26.452 testThreadNoARC[1777:149941] person init index:363
2014-09-16 10:11:26.452 testThreadNoARC[1777:149959] person init index:364
2014-09-16 10:11:26.452 testThreadNoARC[1777:149955] person init index:365
2014-09-16 10:11:26.452 testThreadNoARC[1777:149951] person init index:366
2014-09-16 10:11:26.452 testThreadNoARC[1777:149958] person init index:367
2014-09-16 10:11:26.466 testThreadNoARC[1777:149975] person init index:368
2014-09-16 10:11:26.466 testThreadNoARC[1777:149964] person init index:369
2014-09-16 10:11:26.466 testThreadNoARC[1777:149971] person init index:370
2014-09-16 10:11:26.466 testThreadNoARC[1777:149863] *** -[CFString release]: message sent to deallocated instance 0x7fdc5bec77b0

它每次都在线程 1 崩溃,我不知道为什么会这样。 我认为 Person 对象已被释放,可能会再次释放以使崩溃。 但每次我运行代码时,它的崩溃日志都是一样的。 相同的代码在 ARC 上运行良好。

【问题讨论】:

【参考方案1】:

您的 Person 初始化程序中有这一行:

    _indexStr = [NSString stringWithFormat:@"%d",index];

stringWithFormat: 消息返回一个自动释放的值。您将其直接存储到由 retain 属性管理的实例变量中。由于您绕过了 setter,因此 setter 没有机会保留它。一旦自动释放池被耗尽,字符串就会被释放。由于您从未保留它,因此系统会取消分配它。现在_indexStr 是一个悬空指针。

稍后,在-[Person dealloc] 中,您可以这样做:

self.indexStr = nil;

由于indexStrretain 属性,它的setter 看起来像这样:

- (void)setIndexStr:(NSString *)value 
    NSString *oldValue = _indexStr;
    [value retain];
    _indexStr = value;
    [oldValue release];

这意味着当设置器执行[oldValue release] 时,它会将release 发送到那个悬空指针。这就是你崩溃的地方。

最好的办法是停止使用 MRC开始使用 ARC

在 MRC 下,您可以通过多种方式在 Person 初始化程序中正确保留字符串。这些都可以:

    _indexStr = [[NSString stringWithFormat:@"%d",index] retain];

    // or

    self.indexStr = [NSString stringWithFormat:@"%d",index]

    // or

    _indexStr = [[NSString alloc] initWithFormat:@"%d", index];

【讨论】:

【参考方案2】:

您没有保留用于_indexStr 的字符串。变化:

_indexStr = [NSString stringWithFormat:@"%d",index];

到:

_indexStr = [[NSString stringWithFormat:@"%d",index] retain];

【讨论】:

以上是关于@synchronized 在 MRC 中不起作用,我的应用程序在多线程中崩溃的主要内容,如果未能解决你的问题,请参考以下文章

窗口挂钩在 Windows 7 中不起作用,但在 Windows xp 中不起作用

为啥 heightForHeaderInSection 在 iOS 4.3 中不起作用?

为啥 IOCP 在 BeginExecuteReader 中不起作用

NSWorkSpace' showSearchResultsForQueryString:在 10.14 中不起作用

为啥这个下拉菜单在 IE 中不起作用?

为啥 setVisibility() 在 onResumeFragments() 中不起作用?