搜索
您的当前位置:首页正文

iOS多线程操作时一些要注意的安全问题

来源:二三四教育网
- (void)viewDidLoad {
    [super viewDidLoad];

    self.asStr = @"string is very first";

    [self performSelector:@selector(doSomething) withObject:nil afterDelay:0.5];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSLog(@"before sleep %@",self.asStr);
        sleep(3);
        NSLog(@"after sleep %@",self.asStr);
    });
}

- (void)doSomething {
    self.asStr = @"string has changed";
}

执行结果

2016-08-31 20:58:43.927 HomePageTest[68018:535737] before sleep string is very first
2016-08-31 20:58:46.927 HomePageTest[68018:535737] after sleep string has changed

会发现在异步执行中如果asStr改变了,那么异步线程里的asStr也会改变这样就没法保证异步对资源独占操作。

如果在异步block里创建一个str赋值如下代码

- (void)viewDidLoad {
    [super viewDidLoad];

    self.asStr = @"string is very first";

    [self performSelector:@selector(doSomething) withObject:nil afterDelay:0.5];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSString *str = self.asStr;
        NSLog(@"before sleep %@",str);
        sleep(3);
        NSLog(@"after sleep %@",str);
    });
}

- (void)doSomething {
    self.asStr = @"string has changed";
}

执行结果

2016-08-31 20:59:50.094 HomePageTest[68075:537624] before sleep string is very first
2016-08-31 20:59:53.097 HomePageTest[68075:537624] after sleep string is very first

这样新的string就不会受到外部改变的影响,但是如果在这个赋值时刻self.asStr已变成野指针那么后面的操作还是会出错,虽然这样情况不是那么容易出现。

如何防止这种情况呢,可以看看下面的代码

- (void)viewDidLoad {
    [super viewDidLoad];

    self.asStr = @"string is very first";

    [self performSelector:@selector(doSomething) withObject:nil afterDelay:0.5];

    __weak __typeof(self.asStr) weakString = self.asStr;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        __strong __typeof(weakString) strongString = weakString;
        if(strongString) {
            NSLog(@"before sleep %@",strongString);
            sleep(3);
            NSLog(@"after sleep %@",strongString);
        }
    });
}

- (void)doSomething {
    self.asStr = @"string has changed";
}

执行结果

2016-08-31 21:00:24.457 HomePageTest[68131:538976] before sleep string is very first
2016-08-31 21:00:27.461 HomePageTest[68131:538976] after sleep string is very first

weakString会在self.asStr释放时置为nil,如果不是nil时,能够确保对象在block调用的完整周期里面被retain,如果被抢占对strongString的执行会继续并且会产生一样的值,如果strongString执行到时是nil,那么block不能正确执行前已经返回,这样就不会出现先前那样的问题。

还可以用锁来保证多个线程对一份资源在操作时不会被更改

@interface HomeViewController () {
    pthread_mutex_t _mutex;
}
@end

@implementation HomeViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    pthread_mutex_init(&_mutex, NULL);
    self.asStr = @"string is very first";

    [self performSelector:@selector(doSomething) withObject:nil afterDelay:0.5];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        pthread_mutex_lock(&_mutex);
        self.asStr = @"string has changed in global queue";
        NSLog(@"before sleep %@",self.asStr);
        sleep(3);
        NSLog(@"after sleep %@",self.asStr);
        pthread_mutex_unlock(&_mutex);

    });

}

- (void)doSomething {
    pthread_mutex_lock(&_mutex);
    self.asStr = @"string has changed";
    pthread_mutex_unlock(&_mutex);
}

- (void)dealloc
{
    pthread_mutex_destroy(&_mutex);
}

执行结果

2016-08-31 21:01:00.351 HomePageTest[68174:540038] before sleep string has changed in global queue
2016-08-31 21:01:03.354 HomePageTest[68174:540038] after sleep string has changed in global queue
Top