注册 登录
主题 : 究竟GCD里线程和队列是一种什么关系,求解惑
级别: 新手上路
UID: 555134
精华: 0
发帖: 5
可可豆: 14 CB
威望: 14 点
在线时间: 60(时)
注册时间: 2016-04-05
最后登录: 2018-05-25
0 楼:  发表于: 2018-04-27 15:19    发自: Web Page
来源于 一般提问 分类

究竟GCD里线程和队列是一种什么关系,求解惑   

GCD小菜,以前计算机原理说,线程是CPU调度的基本单位,那么GCD的block肯定是运行在某个线程上的,
直到我看到了下面这段代码....居然不会死锁??!!
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
dispatch_queue_t queue_t = dispatch_queue_create("myConsoleQueue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue_t, ^{
NSLog(@"1. current thread = %@", [NSThread currentThread]);
});
NSLog(@"2. current thread = %@", [NSThread currentThread]);
return 0;
}
还看了http://www.cocoachina.com/ios/20160802/17259.html这篇文章,
突然觉得好像GCD的死锁不是跟线程相关的,而是跟队列有关的(向当前队列重复同步提交 block)。
看完这篇文章的解释,我并不能完全理解,相反线程死锁的概念在我的世界观中频临崩溃,还强加了一些队列的概念在里面。
究竟GCD里线程和队列是一种什么关系,有人能解释清楚吗。


级别: 骑士

状态: 连续签到 - [62天]
UID: 554098
精华: 0
发帖: 243
可可豆: 632 CB
威望: 519 点
在线时间: 461(时)
注册时间: 2016-03-29
最后登录: 2018-08-13
1 楼:  发表于: 2018-04-27 15:53    发自: Web Page
你错误地理解了线程与队列的关系,队列上是放任务的,而线程是去执行队列上的任务的,为什么你的代码不会死锁.我们一步步地去分析.
dispatch_queue_t queue_t = dispatch_queue_create("myConsoleQueue", DISPATCH_QUEUE_SERIAL);这句代码的意思是我在主队列上放一个任务,任务是创建了一个串行队列
dispatch_sync(queue_t, ^{
NSLog(@"1. current thread = %@", [NSThread currentThread]);
});这句代码的意思是,我在主队列上放一个任务,任务是将一个同步任务放在我们的queue_t的串行队列上.学过GCD的应该都要知道,同步任务放在串行队列上是不开辟线程的(由当前线程执行,代码中显而易见,由主线程去执行),这时候主队列会卡住,因为主队列在等待这个dispatch_sync的返回值.然后主线程青睐了你的串行队列queue_t,执行了NSLog(@"1. current thread = %@", [NSThread currentThread]);这个任务后,dispatch_sync返回了一个值.主队列不会卡住,这时候主线程再青睐了主队列后,又能继续往下走了.
????所以你的这句代码是非常危险的,如果你的同步任务不是 NSLog(@"1. current thread = %@", [NSThread currentThread]);而是一个耗时操作,你的主队列会一直在等待同步任务的返回值,在任务结束前,你点UI是没有任何反应的.
级别: 新手上路
UID: 555134
精华: 0
发帖: 5
可可豆: 14 CB
威望: 14 点
在线时间: 60(时)
注册时间: 2016-04-05
最后登录: 2018-05-25
2 楼:  发表于: 2018-04-27 17:12    发自: Web Page
回 1楼(ATM) 的帖子
这时候主队列会卡住,为什么是主队列卡住,而不是主线程卡住,当前不是在主线程上运行吗?
当前有一个主线程,有一个主队列和一个串行队列,队列的任务是放到主线程上去执行的,因为它是CPU调度的基本单位,当前主线程卡住了,然后怎么在当前主线程上再去调度别的队列的block。
级别: 新手上路
UID: 555134
精华: 0
发帖: 5
可可豆: 14 CB
威望: 14 点
在线时间: 60(时)
注册时间: 2016-04-05
最后登录: 2018-05-25
3 楼:  发表于: 2018-04-27 17:26    发自: Web Page
在没有GCD队列的概念之前,我知道要线程同步等待的任务,必然是其它线程去执行的,自己等待自己去执行必然是会引起死锁,没有遇到这段代码之前我对GCD的理解都是很美好的,现在我突然开始有点疑惑了。

我的理解是:主线程会在循环里执行主队列和串行队列的任务(block), 现在主队列的block卡住了,必然会导致主线程被卡住,除非队列的block执行有一种超时机制,超时后再去执行跟它同级的串行队列的任务(这里是由于同步等待导致的超时),但是这个超时时间也是一个很值得考究的问题,当然这只是我一种猜测,感觉这样可以解释得通,但是有点牵强,实在是不敢带着这种疑惑去猜测和写代码。
级别: 骑士

状态: 连续签到 - [62天]
UID: 554098
精华: 0
发帖: 243
可可豆: 632 CB
威望: 519 点
在线时间: 461(时)
注册时间: 2016-03-29
最后登录: 2018-08-13
4 楼:  发表于: 2018-04-27 18:30    发自: Web Page
回 2楼(sunwillshine) 的帖子
主线程不会卡的,只会在多个队列上来回切换.只是主队列的优先级比较高,如果queue_t是主队列,那么你的代码将会死锁
级别: 新手上路
UID: 507345
精华: 0
发帖: 11
可可豆: 11 CB
威望: 11 点
在线时间: 400(时)
注册时间: 2015-09-18
最后登录: 2018-08-10
5 楼:  发表于: 2018-05-02 09:28    发自: Web Page
首先你要理解同步和异步执行的概念,同步和异步目的不是为了是否创建一个新的线程,同步会阻塞当前函数的返回,异步函数会立即返回执行下面的代码,上面的例子,sync主线程等待函数的返回,函数在主线程中执行,主线程执行完,函数返回,继续往下执行,队列是一种数据结构,队列有FIFO,LIFO等,控制任务的执行顺序,至于是否开辟一个新的线程,因为同步函数会等待函数的返回,所以在当前线程执行就行了,没必要浪费资源再开辟新的线程,如果是异步函数,当前线程需要立即函数返回,然后往下执行,所以函数里面的任务必须要开辟一个新的线程去执行这个任务。
[ 此帖被2739160在2018-05-02 09:46重新编辑 ]

级别: 精灵王

状态: 连续签到 - [165天]
UID: 602138
精华: 0
发帖: 846
可可豆: 1723 CB
威望: 1340 点
在线时间: 344(时)
注册时间: 2016-12-29
最后登录: 2018-08-17
6 楼:  发表于: 2018-05-02 10:53    发自: Web Page
感觉楼上的几位都没有get到楼主的意思。虽然说的内容是对的。哈
楼主:突然觉得好像GCD的死锁不是跟线程相关的,而是跟队列有关的(向当前队列重复同步提交 block)。
他疑惑的是发生死锁应该是线程死锁,但是这里操作的感觉和队列有"耦合"(姑且这么说吧)。

我的一些拙劣看法,发生死锁的本质还是线程死锁。这是毋容置疑的。但是为什么楼主贴的代码不会发生死锁是因为线程没有死锁,这里虽然是串行队列、也是主线程(同步任务,没有开辟新线程)。但是任务调度的队列并没有让任务(线程)互相等待。比如A对C说,我有个任务,你现在就执行,我后边的操作要用(楼主代码中的队列)。B对C说,我有个任务,你完成就行(主队列任务,异步执行),然后C(主线程),他优先完成A的紧急任务再完成B的,完成两个任务就行了。这里用的是两个队列,队列之间的线程调度没有互相等待。

如果像4楼说的。换成主队列的话。会造成死锁。因为队列是先进先出的,就像A说我需要C完成一个任务,现在立马要完成(代码控制的同步任务),我后边立马要用,压入一个任务。然后A说我要C完成一个任务,完成就行了(主线程队列又加入一个任务)。这时候先进先出的特性应该是先执行A说的第一个任务。但是这个任务要执行的操作又放在的主线程的后边。主线程队列情况: first-> 任务一 -> 任务二 -> 任务一的操作 。任务二需要等待任务一执行完才能执行。任务一需要执行的操作又得等待任务二的完成。这造成了互相等待,这里的队列只有主线程队列,这导致了队列中的线程执行造成了互相等待。发生死锁。

同理。将主线程队列换成一个有异步线程任务的串行队列去执行同步任务也会发生死锁。简单的说就是串行队列执行异步任务了。还让他执行同步任务,就会发生死锁。因为串行队列只有一个线程,这个线程又要执行同步任务又要执行异步任务,造成线程的互相等待。
级别: 版主

状态: 连续签到 - [7天]
UID: 123750
精华: 2
发帖: 2282
可可豆: 3698 CB
威望: 3619 点
在线时间: 1831(时)
注册时间: 2012-02-15
最后登录: 2018-08-17
7 楼:  发表于: 2018-05-02 11:14    发自: Web Page
死锁说的就是线程死锁,队列,不管是串行队列还是并行队列都是fifo 根本谈不上锁的概念,也就更谈不上死锁

线程和队列完全就是完全不搭边的两个概念,线程就是你cpu的处理能力,队列就是一个任务容器,cpu从容器中取出任务,然后放到线程去执行 ,他俩之间就这点联系


分析你这段代码,实际上是一个线程(主线程) 2个队列(主队列、queue_t)

1、主线程首先执行主队列的任务 dispatch_queue_t queue_t = dispatch_queue_create("myConsoleQueue", DISPATCH_QUEUE_SERIAL);
2、主线程继续执行 dispatch_sync(queue_t, ^{

3、主线程执行  queue_t 任务,也就是里面的两个nslog

4、主线程 执行完毕 queue_t 任务 任务之后切回 主队列继续执行主队列任务(已经没有了)





<null>
级别: 精灵王

状态: 连续签到 - [165天]
UID: 602138
精华: 0
发帖: 846
可可豆: 1723 CB
威望: 1340 点
在线时间: 344(时)
注册时间: 2016-12-29
最后登录: 2018-08-17
8 楼:  发表于: 2018-05-02 11:45    发自: Web Page
回 7楼(wszcug) 的帖子
大佬。。好久不见。甚是想念。
级别: 侠客

状态: 连续签到 - [97天]
UID: 527749
精华: 0
发帖: 115
可可豆: 680 CB
威望: 474 点
在线时间: 374(时)
注册时间: 2015-12-01
最后登录: 2018-08-16
9 楼:  发表于: 2018-05-02 11:52    发自: Web Page
mack一下
快快乐乐过好每一天!
描述
快速回复

关注本帖(如果有新回复会站内信通知您)

发帖、回帖都会得到可观的积分奖励。查看论坛积分规则

按"Ctrl+Enter"直接提交
    顶部