多线程底层探索下

3 篇文章 0 订阅

多线程底层探索

源码中的死锁

请添加图片描述

当代码运行到这里时线程会死锁,接下来从源码观察
通过汇编看到运行以后会来到这个方法__DISPATCH_WAIT_FOR_QUEUE__,然后打开源码
请添加图片描述
然后再进一步看看_dq_state_drain_locked_by源码

DISPATCH_ALWAYS_INLINE
static inline bool
_dq_state_drain_locked_by(uint64_t dq_state, dispatch_tid tid)
{
	return _dispatch_lock_is_locked_by((dispatch_lock)dq_state, tid);
}

直接返回了_dispatch_lock_is_locked_by,参数是线程的id继续查看

DISPATCH_ALWAYS_INLINE
static inline bool
_dispatch_lock_is_locked_by(dispatch_lock lock_value, dispatch_tid tid)
{
	// equivalent to _dispatch_lock_owner(lock_value) == tid
	return ((lock_value ^ tid) & DLOCK_OWNER_MASK) == 0;
}

查看DLOCK_OWNER_MASK宏定义为:#define DLOCK_OWNER_MASK ((dispatch_lock)0xfffffffc)
知道DLOCK_OWNER_MASK是一个比较大的数,只有在tid & DLOCK_OWNER_MASK为0的时候这里才会返回yes
因此得出结论:
在这里插入图片描述

然后验证:
在这里插入图片描述
果然如此。

函数-同步函数和异步函数

同步函数:立即执行,堵塞当前线程 不具备开辟线程的能力
异步函数:可以开辟子线程-不会立即执行-不会堵塞主线程

同步函数的实现:

DISPATCH_NOINLINE
void
dispatch_sync(dispatch_queue_t dq, dispatch_block_t work)
{
	uintptr_t dc_flags = DC_FLAG_BLOCK;
	if (unlikely(_dispatch_block_has_private_data(work))) {
		return _dispatch_sync_block_with_privdata(dq, work, dc_flags);
	}
	_dispatch_sync_f(dq, work, _dispatch_Block_invoke(work), dc_flags);
}

unlikely :是系统级别小概率发生的事件
_dispatch_Block_invoke: 是block执行的代码
宏:
#define _dispatch_Block_invoke(bb)
((dispatch_function_t)((struct Block_layout *)bb)->invoke)
从这里可以看出block的本质还是一个Block_layout的结构体,然后实际上执行的是invoke指针指向的代码块
接下来通过查看_dispatch_sync_f源码看看_dispatch_Block_invoke什么时候被执行。

DISPATCH_NOINLINE
static void
_dispatch_sync_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func,
		uintptr_t dc_flags)
{
	_dispatch_sync_f_inline(dq, ctxt, func, dc_flags);
}
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_sync_f_inline(dispatch_queue_t dq, void *ctxt,
		dispatch_function_t func, uintptr_t dc_flags)
{
	if (likely(dq->dq_width == 1)) {
		return _dispatch_barrier_sync_f(dq, ctxt, func, dc_flags);
	}

	if (unlikely(dx_metatype(dq) != _DISPATCH_LANE_TYPE)) {
		DISPATCH_CLIENT_CRASH(0, "Queue type doesn't support dispatch_sync");
	}

	dispatch_lane_t dl = upcast(dq)._dl;
	// Global concurrent queues and queues bound to non-dispatch threads
	// always fall into the slow case, see DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE
	if (unlikely(!_dispatch_queue_try_reserve_sync_width(dl))) {
		return _dispatch_sync_f_slow(dl, ctxt, func, 0, dl, dc_flags);
	}

	if (unlikely(dq->do_targetq->do_targetq)) {
		return _dispatch_sync_recurse(dl, ctxt, func, dc_flags);
	}
	_dispatch_introspection_sync_begin(dl);
	_dispatch_sync_invoke_and_complete(dl, ctxt, func DISPATCH_TRACE_ARG(
			_dispatch_trace_item_sync_push_pop(dq, ctxt, func, dc_flags)));
}

没有保存任务马上执行了。

异步函数:

void
dispatch_async(dispatch_queue_t dq, dispatch_block_t work)
{
	dispatch_continuation_t dc = _dispatch_continuation_alloc();
	uintptr_t dc_flags = DC_FLAG_CONSUME;
	dispatch_qos_t qos;

	qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);
	_dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}
static inline dispatch_qos_t
_dispatch_continuation_init(dispatch_continuation_t dc,
		dispatch_queue_class_t dqu, dispatch_block_t work,
		dispatch_block_flags_t flags, uintptr_t dc_flags)
{
	void *ctxt = _dispatch_Block_copy(work);

	dc_flags |= DC_FLAG_BLOCK | DC_FLAG_ALLOCATED;
	if (unlikely(_dispatch_block_has_private_data(work))) {
		dc->dc_flags = dc_flags;
		dc->dc_ctxt = ctxt;
		// will initialize all fields but requires dc_flags & dc_ctxt to be set
		return _dispatch_continuation_init_slow(dc, dqu, flags);
	}

	dispatch_function_t func = _dispatch_Block_invoke(work);
	if (dc_flags & DC_FLAG_CONSUME) {
		func = _dispatch_call_block_and_release;
	}
	return _dispatch_continuation_init_f(dc, dqu, ctxt, func, flags, dc_flags);
}
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_continuation_async(dispatch_queue_class_t dqu,
		dispatch_continuation_t dc, dispatch_qos_t qos, uintptr_t dc_flags)
{
#if DISPATCH_INTROSPECTION
	if (!(dc_flags & DC_FLAG_NO_INTROSPECTION)) {
		_dispatch_trace_item_push(dqu, dc);
	}
#else
	(void)dc_flags;
#endif
	return dx_push(dqu._dq, dc, qos);

//#define dx_push(x, y, z) dx_vtable(x)->dq_push(x, y, z)。
//#define dx_vtable(x) (&(x)->do_vtable->_os_obj_vtable)。区分类型
}

保存了block— RAC – 函数式编程
线程的相关操作

例题 - 以及答案 解析

可降下面的代码块代码,新建工程直接覆盖到viewcontroller.m的文件里面去

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic ,assign) int num;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
        
    [self test2];
    
}


-(void)test1 {
    
    dispatch_queue_t queue = dispatch_queue_create("zxy", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
      
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        
        NSLog(@"2");
    });
    //由于当前线程调度不确定,所以3可能在1-2前也可能在1-2后。但是鉴于开辟线程需要时间所以默认3是最快。可以确定的是0789会跟在3的后面。
    dispatch_sync(queue, ^{
        sleep(2);
        NSLog(@"3");
    });
    
    NSLog(@"0");
    dispatch_async(queue, ^{
        NSLog(@"7");
    });
    dispatch_async(queue, ^{
        NSLog(@"8");
    });
    dispatch_async(queue, ^{
        NSLog(@"9");
    });
}

-(void)test2 {
    
    dispatch_queue_t t = dispatch_queue_create("lg", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"1");
    dispatch_sync(t, ^{
        NSLog(@"2");//当前在串行队列所以2先于5,由于同步执行所以依据FIFO,先完成2,4再到3
        dispatch_async(t, ^{
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    NSLog(@"5");
    //12435
}

- (void)test3 {
    self.num = 0;
    while (self.num < 100) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.num ++;
        });
    }
    
    NSLog(@"self.num = %d",self.num);
    /*
     因为while会堵塞线程 所以按照线程的调度来看输出肯定大于等于100*/
}

- (void)test4 {
    self.num = 0;
    for (int i = 0; i < 100; i ++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.num ++;
        });
    }
    NSLog(@"self.num = %d",self.num);
    /** for循环不会堵塞线程,所以输出可能是0-100*/
}


-(void)test5 {
    
    dispatch_queue_t t = dispatch_queue_create("lg", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1");
    dispatch_sync(t, ^{
        NSLog(@"2");
        dispatch_async(t, ^{
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    NSLog(@"5");
    
    // 12435
}

-(void)test6 {
    
    dispatch_queue_t t = dispatch_queue_create("lg", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"1");
    dispatch_async(t, ^{
        NSLog(@"2");
        dispatch_sync(t, ^{
            NSLog(@"3");//因为同步执行导致在当前任务需要先执行完3再到4
        });
        NSLog(@"4");
    });
    NSLog(@"5");
    
    //15234
}

@end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值