dispatch_sync() 的秘密!它一定会造成死锁吗?

dispatch_sync() 的秘密!它一定会造成死锁吗?

平时我们可能很少用到 dispatch_sync ,只是知道,如果调用 dispatch_sync(dispatch_get_main_queue(), block) 的话,会阻塞主线程。但事实并非如此。
另外,dispatch_sync() 和 dispatch_async() 可不仅仅是差了一个字母,也不仅仅是同步和异步的差别。

在看之前,建议首先要明确,队列、线程、任务,的关系。我发现很多人会把队列和线程搞混。一定要注意!

首先,dispatch_sync 的作用是,往某队列(第一个参数)中,添加一个同步任务(第二个参数)。

那么我们通常说其会造成主线程死锁的情况,比如场景0会造成死锁的情况。这大家都知道,就不多说了。

为了方便下面的讲解,先贴上官方文档的一个解释:
As an optimization, dispatch_sync() invokes the workitem on the thread which
submitted the workitem, except when the passed queue is the main queue or a queue targetting it (See dispatch_queue_main_t, dispatch_set_target_queue()).

作为优化,dispatch_sync() 执行它的任务时,会优先选择添加这个任务的线程,除非第一个参数你传入了主队列。

下面举例说明:
(PS: queue 和 queue2 是 serial 还是 concurrent 对本例影响不大)


场景0:

 1. (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_sync(dispatch_get_main_queue(), ^{
    	NSLog(@"同步任务在 %@ 执行", [NSThread currentThread]);
    });
}

在场景0中,是在主线程中,往主队列添加一个同步任务,结果就造成死锁,主线程被阻塞。是相互等待的情况。

  1. 主线程正在执行主队列的任务。
  2. 一个同步任务过来了
  3. 于是,主线程立即等待
  4. 同步任务在等主线程当前任务完成,然而主线程在等待这个同步任务执行。
  5. 于是就造成了相互等待的情况。

场景1:

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_queue_t queue = dispatch_queue_create("com.gcd.serial", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"异步任务在 %@ 执行", [NSThread currentThread]);
        dispatch_sync(queue, ^{
            NSLog(@"同步任务在 %@ 执行", [NSThread currentThread]);
        });
    });
}

在场景1中,首先是在主线程中,往 queue 添加一个异步任务;然后子线程中,又往queue添加一个同步任务,就和场景0的情况是一样的,会造成死锁。


场景2:

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_queue_t queue = dispatch_queue_create("com.gcd.serial", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("com.gcd.concurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
    	NSLog(@"任务", [NSThread currentThread]);
    	dispatch_sync(queue2, ^{
    		NSLog(@"同步任务%@", [NSThread currentThread]);
    	});
    });
}

在场景2中,首先,是在主线程中,往queue添加一个异步任务;然后在子线程中,往queue2添加一个同步任务。

这种情况不会死锁,可以正常运行。

最终,这两个任务都会在同一个线程中执行,假如第一个 NSLog 打印线程 number = 3,那么第二个NSLog打印的也一定是3,因为会优先选择添加这个任务的线程


场景3:

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_queue_t queue = dispatch_queue_create("com.gcd.serial", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
    	NSLog(@"任务", [NSThread currentThread]);
    	//这里要注意了,并不会死锁!
    	dispatch_sync(dispatch_get_main_queue(), ^{
    	    NSLog(@"同步任务%@", [NSThread currentThread]);
    	});
    });
}

首先,是在主线程中,往queue添加一个异步任务;然后在子线程中,往主队列添加一个同步任务。

这种情况不会死锁,可以正常运行。

最终,第一个任务在子线程(比如number = 3)执行 ;第二个任务在主线程中执行,官方文档解释:除非第一个参数你传入了主队列


总结

  • 队列中的任务,最终会由线程调度,GCD管理线程的生命周期。
  • dispatch_sync() 是线程同步操作,其作用就是阻塞线程,先让它的block执行完毕,才会返回。
  • dispatch_sync() 造成死锁的条件是:如果在同一个队列(不管是不是主队列)添加同步任务,就会死锁,反之则不会。
- (void)viewDidLoad {
    [super viewDidLoad];
    //队列1
    dispatch_queue_t queue = dispatch_queue_create("com.gcd.serial", DISPATCH_QUEUE_SERIAL);
    //队列2
    dispatch_queue_t queue2 = dispatch_queue_create("com.gcd.concurrent", DISPATCH_QUEUE_CONCURRENT);
    //主线程中,往 queue 添加一个异步任务,是异步任务,不会等待。
    dispatch_async(queue, ^{
    	NSLog(@"异步任务在 %@" 执行, [NSThread currentThread]);
    	//这里是子线程,比如 number = 3
    	
    	//在子线程(number = 3),往 queue2 添加一个同步任务,此时子线程(number = 3)会立即等待,即被阻塞,等待block执行完毕
	//添加一个同步任务到queue2中
	dispatch_sync(queue2, ^{
	    //这个任务也会在number = 3 的子线程中执行
	    NSLog(@"同步任务在 %@ 执行", [NSThread currentThread]);
	});
		
	//同步任务执行完毕,继续执行异步任务
	NSLog(@"异步任务完成!")
    });
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
def write(self, vals): audit = self.env['approval.flow'].search([('approval_cannot_run_id', '=', '修改')]) value_list = list(vals.keys()) receive_list = [] value_list_not_in_receive_list = [i for i in value_list if i not in receive_list] value_list = value_list_not_in_receive_list # 应付 dispatch_number = 0 dispatch_id = self.env['roke.dispatch.order.management.price.approve'].search([('order_id.id', '=', self.id)]) dispatch_list = ['value03', 'value04', 'value05', 'value06', 'value07', 'value08'] if dispatch_id: for rec in value_list: for dispatch_list_id in dispatch_list: if rec == dispatch_list_id: if dispatch_id.approval_status != '未提' and dispatch_id.approval_status != '驳回': raise UserError("应付费用已开始审核不允许修改") value_list_not_in_dispatch_list = [i for i in value_list if i not in dispatch_list] value_list = value_list_not_in_dispatch_list dispatch_number = 1 break if dispatch_number: break # 基础 base_number = 0 base_list = ['client', 'department_manager', 'box_number', 'shipping_companies', 'field_station', 'ship_name_voyage', 'port_of_discharge', 'box_type', 'code', 'bill__of_lading_number', 'departure_date', 'lead_sealing', 'booking_time', 'date_of_pick_up', 'encore_date', 'set_port_date', 'estimated_range', 'destination_port_arrival_time'] if value_list: for rec in value_list: for base_list_id in base_list: if rec == base_list_id: if dispatch_id: if dispatch_id.approval_status != '未提' and dispatch_id.approval_status != '驳回': raise UserError("应付费用已开始审核不允许修改") base_number = 1 break if base_number: break return super(Rokedispatchordermanagement, self).write(vals) audit审核完成如果是修改不能修改如果不是可以修改怎么写可以实现
06-13

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值