赞
踩
在OC中,如果多个线程要执行同一份代码,那么可能会出现问题。这种情况下,通常使用锁来实现某种同步机制。
在GCD出现之前,有两种方法:
- (void)someMethod
{
@synchronized(self){
//Safe
}
}
这种会根据给定的对象(self),自动创建一个锁,并等待块中的代码执行完毕。
执行到这段代码结尾处,锁就释放了。
然鹅,过多的使用@synchronized(self),会降低代码效率,因为共用同一个锁的那些同步块,都必须按顺序执行
_lock = [[NSLock alloc] init];
- (void)someMethod
{
[_lock lock];
//Safe
[_lock unlock];
}
也可以使用递归锁:NSRecursiverLock
,线程可以多次持有该锁,而不会出现死锁(deadlock)现象。
在设置属性的时候,如果需要属性为“原子的”,则经常需要用到同步,使用atomic来修饰属性,就可以实现。
但无法保证访问该对象时绝对是线程安全的。
有种简单而高效的方法可以代替同步块或锁对象,那就是使用“串行同步队列”
将读写操作都安排在同一个队列里,即可保证数据同步
例如:
即可实现数据的同步
还可以将设置方法写成异步执行:
GCD有一个栅栏(barrier),可以实现多读单写功能。
dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
举个例子:
_syncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - (NSString *)someString { __block NSString *localSomeString; dispatch_sync(_syncQueue, ^{ localSomeString = _someString; }); return localSomeString; } - (void)setSomeString:(NSString *)someString{ dispatch_barrier_async(_syncQueue, ^{ _someString = someString; }); }
经过与之前写的一篇有关多读单写的文章多线程学习(二)有些地方有冲突,有些地方有记录不清的地方,做统一验证
有几处疑问:
两篇文章都提到了不能使用串行队列
验证:
self.queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_SERIAL);
打印结果:
2022-03-20 11:33:44.526704+0800 008[1941:46200] -[ViewController read]_block_invoke
2022-03-20 11:33:45.528229+0800 008[1941:46200] -[ViewController read]_block_invoke
2022-03-20 11:33:46.530097+0800 008[1941:46200] -[ViewController read]_block_invoke
2022-03-20 11:33:47.535326+0800 008[1941:46200] -[ViewController write]_block_invoke
2022-03-20 11:33:48.540525+0800 008[1941:46200] -[ViewController write]_block_invoke
2022-03-20 11:33:49.544776+0800 008[1941:46200] -[ViewController write]_block_invoke
2022-03-20 11:33:50.546115+0800 008[1941:46200] -[ViewController read]_block_invoke
可以看出,读、写都是每秒执行一次,从而失去了多读单写的功能
验证:
self.queue = dispatch_get_global_queue(0, 0);
- (void)write
{
dispatch_barrier_async(self.queue, ^{
sleep(1);
NSLog(@"%s", __func__);
});
}
结果:
2022-03-20 11:37:00.889954+0800 008[2015:50136] -[ViewController read]_block_invoke
2022-03-20 11:37:00.889936+0800 008[2015:50138] -[ViewController write]_block_invoke
2022-03-20 11:37:00.889946+0800 008[2015:50140] -[ViewController read]_block_invoke
2022-03-20 11:37:00.889989+0800 008[2015:50142] -[ViewController write]_block_invoke
2022-03-20 11:37:00.889960+0800 008[2015:50141] -[ViewController read]_block_invoke
2022-03-20 11:37:00.890017+0800 008[2015:50137] -[ViewController write]_block_invoke
2022-03-20 11:37:00.890017+0800 008[2015:50149] -[ViewController read]_block_invoke
2022-03-20 11:37:00.890041+0800 008[2015:50148] -[ViewController read]_block_invoke
2022-03-20 11:37:00.890098+0800 008[2015:50156] -[ViewController read]_block_invoke
2022-03-20 11:37:00.890096+0800 008[2015:50153] -[ViewController write]_block_invoke
基本上一下就执行完了,写是同步进行的,没有休眠,因此,不满足“单写”
验证:
self.queue = dispatch_get_global_queue(0, 0);
- (void)write
{
dispatch_barrier_sync(self.queue, ^{
sleep(1);
NSLog(@"%s", __func__);
});
}
结果:
2022-03-20 11:38:08.063348+0800 008[2048:51424] -[ViewController write]_block_invoke
2022-03-20 11:38:08.065732+0800 008[2048:51476] -[ViewController read]_block_invoke
2022-03-20 11:38:08.065732+0800 008[2048:51472] -[ViewController read]_block_invoke
2022-03-20 11:38:08.065732+0800 008[2048:51471] -[ViewController read]_block_invoke
2022-03-20 11:38:09.064681+0800 008[2048:51424] -[ViewController write]_block_invoke
2022-03-20 11:38:10.066012+0800 008[2048:51424] -[ViewController write]_block_invoke
2022-03-20 11:38:11.067604+0800 008[2048:51424] -[ViewController write]_block_invoke
2022-03-20 11:38:11.067633+0800 008[2048:51471] -[ViewController read]_block_invoke
2022-03-20 11:38:11.067635+0800 008[2048:51476] -[ViewController read]_block_invoke
2022-03-20 11:38:11.067635+0800 008[2048:51472] -[ViewController read]_block_invoke
2022-03-20 11:38:12.069155+0800 008[2048:51424] -[ViewController write]_block_invoke
读一下就执行完毕,满足多读
写是每一秒执行一次,也满足
但有个小问题,写执行完毕,要执行读的操作的时候,基本上最后一个写和第一个读是同时执行的
验证:
self.queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);
- (void)write
{
dispatch_barrier_sync(self.queue, ^{
sleep(1);
NSLog(@"%s", __func__);
});
}
结果:
2022-03-20 11:41:08.055321+0800 008[2114:54371] -[ViewController read]_block_invoke
2022-03-20 11:41:08.055321+0800 008[2114:54372] -[ViewController read]_block_invoke
2022-03-20 11:41:08.055321+0800 008[2114:54376] -[ViewController read]_block_invoke
2022-03-20 11:41:09.056482+0800 008[2114:54163] -[ViewController write]_block_invoke
2022-03-20 11:41:10.058033+0800 008[2114:54163] -[ViewController write]_block_invoke
2022-03-20 11:41:11.059538+0800 008[2114:54163] -[ViewController write]_block_invoke
2022-03-20 11:41:12.060971+0800 008[2114:54371] -[ViewController read]_block_invoke
2022-03-20 11:41:12.060979+0800 008[2114:54376] -[ViewController read]_block_invoke
满足多读单写
self.queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);
- (void)write
{
dispatch_barrier_async(self.queue, ^{
sleep(1);
NSLog(@"%s", __func__);
});
}
结果:
2022-03-20 11:42:58.414861+0800 008[2159:56378] -[ViewController read]_block_invoke
2022-03-20 11:42:58.414861+0800 008[2159:56382] -[ViewController read]_block_invoke
2022-03-20 11:42:58.414861+0800 008[2159:56383] -[ViewController read]_block_invoke
2022-03-20 11:42:59.420234+0800 008[2159:56382] -[ViewController write]_block_invoke
2022-03-20 11:43:00.425576+0800 008[2159:56382] -[ViewController write]_block_invoke
2022-03-20 11:43:01.426410+0800 008[2159:56382] -[ViewController write]_block_invoke
2022-03-20 11:43:02.431424+0800 008[2159:56378] -[ViewController read]_block_invoke
2022-03-20 11:43:02.431423+0800 008[2159:56380] -[ViewController read]_block_invoke
2022-03-20 11:43:02.431445+0800 008[2159:56382] -[ViewController read]_block_invoke
2022-03-20 11:43:03.436903+0800 008[2159:56378] -[ViewController write]_block_invoke
2022-03-20 11:43:04.440432+0800 008[2159:56378] -[ViewController write]_block_invoke
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。