五个案例让你明白GCD死锁

Sublime Text4代码配色自定义方案 关于Sublime Text对于我的使用体验,只能说内置的代码主题真的都太low了,一点都不好看。所以接下来我分享一下我自定义代码配色。当然,大家也可以通过我给的中文翻译注释来自定义自己喜欢的颜色。废话不多说,直接上代码直接将代码复制粘贴到:Preferences > Customize Color Scheme 即可。},"globals":"foreground": "var(white)", // 前景色。 阅读详情

转自:http://blog.youkuaiyun.com/ios_liang/article/details/49582827


环境信息:

Mac OS X 10.10.5

Xcode 6.4

iOS 8.4

串行与并行

在使用GCD的时候,我们会把需要处理的任务放到Block中,然后将任务追加到相应的队列里面,这个队列,叫做Dispatch Queue。然而,存在于两种Dispatch Queue,一种是要等待上一个执行完,再执行下一个的Serial Dispatch Queue,这叫做串行队列;另一种,则是不需要上一个执行完,就能执行下一个的Concurrent Dispatch Queue,叫做并行队列。这两种,均遵循FIFO原则。

举一个简单的例子,在三个任务中输出1、2、3,串行队列输出是有序的1、2、3,但是并行队列的先后顺序就不一定了。

那么,并行队列又是怎么在执行呢?

虽然可以同时多个任务的处理,但是并行队列的处理量,还是要根据当前系统状态来。如果当前系统状态最多处理2个任务,那么1、2会排在前面,3什么时候操作,就看1或者2谁先完成,然后3接在后面。

串行和并行就简单说到这里,关于它们的技术点其实还有很多,可以自行了解。

同步与异步

串行与并行针对的是队列,而同步与异步,针对的则是线程。最大的区别在于,同步线程要阻塞当前线程,必须要等待同步线程中的任务执行完,返回以后,才能继续执行下一任务;而异步线程则是不用等待。

仅凭这几句话还是很难理解,所以之后准备了很多案例,可以边分析边理解。

GCD API

GCD API很多,这里仅介绍本文用到的。

  1. 系统标准提供的两个队列

     // 全局队列,也是一个并行队列
    
     dispatch_get_global_queue 
    
     // 主队列,在主线程中运行,因为主线程只有一个,所以这是一个串行队列
    
     dispatch_get_main_queue 
    
  2. 除此之外,还可以自己生成队列

     // 从DISPATCH_QUEUE_SERIAL看出,这是串行队列
    
     dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL) 
    
     // 同理,这是一个并行队列
    
     dispatch_queue_create("com.demo.concurrentQueue", DISPATCH_QUEUE_CONCURRENT) 
    

接下来是同步与异步线程的创建:

dispatch_sync(..., ^(block)) // 同步线程

dispatch_async(..., ^(block)) // 异步线程

案例与分析

假设你已经基本了解了上面提到的知识,接下来进入案例讲解阶段。

案例一:

NSLog(@"1"); // 任务1

dispatch_sync(dispatch_get_main_queue(), ^{

    NSLog(@"2"); // 任务2

});

NSLog(@"3"); // 任务3

结果,控制台输出:

1

分析:

dispatch_sync表示是一个同步线程;

dispatch_get_main_queue表示运行在主线程中的主队列;

任务2是同步线程的任务。

首先执行任务1,这是肯定没问题的,只是接下来,程序遇到了同步线程,那么它会进入等待,等待任务2执行完,然后执行任务3。但这是队列,有任务来,当然会将任务加到队尾,然后遵循FIFO原则执行任务。那么,现在任务2就会被加到最后,任务3排在了任务2前面,问题来了:

任务3要等任务2执行完才能执行,任务2由排在任务3后面,意味着任务2要在任务3执行完才能执行,所以他们进入了互相等待的局面。【既然这样,那干脆就卡在这里吧】这就是死锁。

deadlock

案例二:

NSLog(@"1"); // 任务1

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

    NSLog(@"2"); // 任务2

});

NSLog(@"3"); // 任务3

结果,控制台输出:

1

2

3

分析:

首先执行任务1,接下来会遇到一个同步线程,程序会进入等待。等待任务2执行完成以后,才能继续执行任务3。从dispatch_get_global_queue可以看出,任务2被加入到了全局的并行队列中,当并行队列执行完任务2以后,返回到主队列,继续执行任务3。

2

案例三:

dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);

NSLog(@"1"); // 任务1

dispatch_async(queue, ^{

    NSLog(@"2"); // 任务2

    dispatch_sync(queue, ^{  

        NSLog(@"3"); // 任务3

    });

    NSLog(@"4"); // 任务4

});

NSLog(@"5"); // 任务5

结果,控制台输出:

1

5

2

// 5和2的顺序不一定

分析:

这个案例没有使用系统提供的串行或并行队列,而是自己通过dispatch_queue_create函数创建了一个DISPATCH_QUEUE_SERIAL的串行队列。

执行任务1;

遇到异步线程,将【任务2、同步线程、任务4】加入串行队列中。因为是异步线程,所以在主线程中的任务5不必等待异步线程中的所有任务完成;

因为任务5不必等待,所以2和5的输出顺序不能确定;

任务2执行完以后,遇到同步线程,这时,将任务3加入串行队列;

又因为任务4比任务3早加入串行队列,所以,任务3要等待任务4完成以后,才能执行。但是任务3所在的同步线程会阻塞,所以任务4必须等任务3执行完以后再执行。这就又陷入了无限的等待中,造成死锁。

3

案例四:

NSLog(@"1"); // 任务1

dispatch_async(dispatch_get_global_queue(0, 0), ^{

    NSLog(@"2"); // 任务2

    dispatch_sync(dispatch_get_main_queue(), ^{

        NSLog(@"3"); // 任务3

    });

    NSLog(@"4"); // 任务4

});

NSLog(@"5"); // 任务5

结果,控制台输出:

1

2

5

3

4

// 5和2的顺序不一定

分析:

首先,将【任务1、异步线程、任务5】加入Main Queue中,异步线程中的任务是:【任务2、同步线程、任务4】。

所以,先执行任务1,然后将异步线程中的任务加入到Global Queue中,因为异步线程,所以任务5不用等待,结果就是2和5的输出顺序不一定。

然后再看异步线程中的任务执行顺序。任务2执行完以后,遇到同步线程。将同步线程中的任务加入到Main Queue中,这时加入的任务3在任务5的后面。

当任务3执行完以后,没有了阻塞,程序继续执行任务4。

从以上的分析来看,得到的几个结果:1最先执行;2和5顺序不一定;4一定在3后面。

4

案例五:

dispatch_async(dispatch_get_global_queue(0, 0), ^{

    NSLog(@"1"); // 任务1

    dispatch_sync(dispatch_get_main_queue(), ^{

        NSLog(@"2"); // 任务2

    });

    NSLog(@"3"); // 任务3

});

NSLog(@"4"); // 任务4

while (1) {

}

NSLog(@"5"); // 任务5

结果,控制台输出:

1

4

// 1和4的顺序不一定

分析:

和上面几个案例的分析类似,先来看看都有哪些任务加入了Main Queue:【异步线程、任务4、死循环、任务5】。

在加入到Global Queue异步线程中的任务有:【任务1、同步线程、任务3】。

第一个就是异步线程,任务4不用等待,所以结果任务1和任务4顺序不一定。

任务4完成后,程序进入死循环,Main Queue阻塞。但是加入到Global Queue的异步线程不受影响,继续执行任务1后面的同步线程。

同步线程中,将任务2加入到了主线程,并且,任务3等待任务2完成以后才能执行。这时的主线程,已经被死循环阻塞了。所以任务2无法执行,当然任务3也无法执行,在死循环后的任务5也不会执行。

最终,只能得到1和4顺序不定的结果。

5


Ollama内网离线部署大模型实战:从模型文件到私有化服务 本文详细介绍了如何在内网离线环境下,利用Ollama部署私有化大模型服务。内容涵盖从获取GGUF格式模型文件、手动安装Ollama、编写核心Modelfile配置文件,到创建运行模型、性能调优及安全加固的全流程实战指南,旨在帮助企业安全、可控地构建内部AI能力。 阅读详情

相关推荐

单机多环境部署apollo 2.3.0

理解apollo的整体架构后,对比nacos配置中心功能点,其设计的复杂度以及完整度相较nacos而言更为丰富 对于不同的环境,例如 FAT, PRO 在部署时进程已经完全物理隔离,并且每个环境config/adminservice依赖的数据也完全物理隔离(连接不同的db),在数据隔离与安全方面做的很完善,但同时也提升了架构的复杂度 而 portal 可以管理多个环境,单节点部署虽然有单点问题,但并不会影响业务从configservice读取配置, 挂掉只要重启就可以,只是在

Life is a starting point everywhere 1299

dispatch_async 与 dispatch_get_global_queue 区别

dispatch_async ,dispatch_get_global_queue和 dispatch_get_main_queue的区别 dispatch_async函数会将传入的block块放入指定的queue里运行。这个函数是异步的,这就意味着它会立即返回而不管block是否运行结束(在主队列中除外,在主队列中不会开启新线程,会串行执行任务)。因此,我们可以在block里运行各种耗时的操作...

yanPingWang_8的博客 3803

LaTeX公式转Word竟这么简单?Python三行代码实现学术论文格式无忧

本文介绍如何利用Python的latex2word库,仅需三行代码即可将LaTeX数学公式精准转换为Word原生Office Math对象,解决学术写作中LaTeX与Word格式割裂的难题。该方法支持批量处理、格式保真,并能与Markdown、Jupyter Notebook等工具集成,构建自动化写作流程,实现学术论文格式无忧。

qsc90123456的博客 295

并发编程指南(二)Dispatch Queue

Dispatch Queues Grand Central Dispatch(GCD)调度队列是执行任务的强大工具。 通过调度队列,您可以相对于调用者异步或同步地执行任意代码块。 您可以使用调度队列执行几乎所有在单独线程上执行的任务。 调度队列的优点是它们比相应的线程代码更易于使用,并且执行这些任务的效率更高。 本章介绍了调度队列,以及有关如何使用它们在应用程序中执行常规任务的信息。 如果要使...

szk972092933的博客 1189

CTP-API开发系列之三:柜台系统简介

综合交易平台(Comprehensive Transaction Platform,CTP)是专门为期货公司开发的一套期货经纪业务管理系统,由交易、风险控制和结算三大系统组成。接下来分享的内容,对于期货公司的负责交易、运维同事会比较熟悉,针对CTP-API接口对接的朋友可以了解一下,在接口之上的系统是怎样的。

码上助君的专栏 6194

【物联网】探索NE555:一款经典的集成电路(超详细)

NE555是一种集成电路,其内部结构包括比较器、RS触发器、电压比较器和输出级三个主要功能模块,外部引脚则提供了与其他电路元件进行连接的接口。NE555的设计目的是为了提供一种简单方便的定时器解决方案,它广泛应用于模拟和数字电路中。NE555作为一款经典的集成电路,具备设计简单、易于使用和稳定可靠的特点,在电子领域发展了广泛的应用。从单稳态模式到多稳态模式,再到振荡器模式,NE555可以满足不同的需求,并且可以与其他电路元件灵活组合,扩展其功能。然而,需要注意的是NE555也有一些限制。

Goforyouqp的博客 6万+

GCD详解

一、介绍 1、什么是GCD? Grand Central Dispatch,是苹果公司开发的一套多核编程的底层API。GCD首次发布在Mac OS X 10.6,iOS4及以上也可用。GCD存在于libdispatch.dylib这个库中,iOS程序默认动态加载这个库,无需手动引入。 2、GCD工作原理 让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。一个任务可以是一个Function或是一个block。GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现

xiezhenxiang的专栏 956

逆向淘宝x-mini-wua:从加密算法到设备指纹的生成逻辑

本文深入剖析了淘宝风控核心参数x-mini-wua的生成逻辑与加密算法。通过逆向分析,揭示了其作为设备“身份证”的作用,详细拆解了从硬件信息采集、SG_INNER_DATA文件解密、关键参数提取到最终长wua合成的完整技术链条,并探讨了模拟生成与绕过风控的实战思路及注意事项。

year5的博客 1075

移花接木,玩转CANoe的几种扩展接口应用(五)——串口设备

近期看到粉丝朋友在CANoe自动化测试方面的关注度很大,今天就围绕这个做一个专题,总结一下以往项目上用过的几种CANoe扩展接口,分享出来希望对相关领域的网友有所帮助。本文是该专题的第五篇文章,主要讲解了串口设备的功能配置、连接方法、配置方法、调用方法,最后分析了这种扩展借口应用的特点和适用场景。

Mr.Cssust的博客 2369

WiFi基本概念(六)(L-STF,L-LTF)

L-STF它由10个OFDM symbol(1,0,1,0,1,0,1,0,1,0)构成,每个symbol是0.8us,GI是0.2us,总计10us。Symbol的长度是正常长度的1/4,因此称为Short training field,主要用于快速进行信号检测,信号同步,自动增益控制,接收天线选择(Diversity Selection)。 由于symbol长度是正常的1/4,子载波的宽度是正常的4倍,能进行初略的信道估计,其使用了-24, -20, -16, -12, -8, -4, 4, 8, 1

reekyli的专栏 6860

dispatch_get_global_queue() 与dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT)的区别

Global queues是全局队列是并发队列,并由整个进程共享。进程中存在三个全局队列:高、中(默认)、低三个优先级队列。可以调用dispatch_get_global_queue函数传入优先级来访问队列。 dispatch_queue_create使用户队列,由用户通过dispatch_queue_create来自行创建的串行队列,可以用于完成同步机制

shn_boy的博客 2181

【SpringBoot 4.x 第70节】夯爆了,企业级 API 设计规范落地:状态码、错误码、接口文档与兼容性(超详解)!

🏆 本文收录于 《滚雪球学 Spring Boot 4.x》 专栏。本专栏面向 有一定 Java 基础,但尚未系统学习 Spring Boot 的读者,采用“滚雪球式学习法”:先跑通、再理解、再重构、再上线,带你从第一个 Hello API 开始,逐步完成一个可部署、可监控、可扩展的后端项目。

**My Coding Family** 128

五个案例明白GCD死锁

串行与并行 在使用GCD的时候,我们会把需要处理的任务放到Block中,然后将任务追加到相应的队列里面,这个队列,叫做Dispatch Queue。然而,存在于两种Dispatch Queue,一种是要等待上一个执行完,再执行下一个的Serial Dispatch Queue,这叫做串行队列;另一种,则是不需要上一个执行完,就能执行下一个的Concurrent Dispatch Que...

banhan7136的博客 127

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

五个案例让你明白GCD死锁(转)

转自:http://ios.jobbole.com/82622/ 死锁一直都是在使用多线程时,需要注意的一个问题。以前对同步、异步,串行、并行只有一个模糊的概念,想想也是时候整理一下了。再看看之前的博客,已经很久没有干货了【说得好像之前有干货一样】,所以,这篇博客,我尽最大努力,也借鉴了很多其他博客中的例子,来讲解GCD死锁问题。 环境信息: Mac OS X...

weixin_30407099的博客 92

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

iOS 多线程编程 GCD 死锁

GCD:Grand Central DiapathGCD多线程中的几组概念: 任务:即操作,你想要干什么,说白了就是一段代码,在GCD中的一个block就是一个任务。 任务的执行方式有两种: 同步执行和异步执行,两者的区分在于是否会阻塞当前线程直到block中的任务执行完毕。 同步执行(sync) :会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行。

学海无涯苦作舟 890

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

一篇专题让你秒懂GCD死锁问题!

为什么80%的码农都做不了架构师?>>> ...

weixin_34261739的博客 287

GCD死锁及取消

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34289454的博客 322
上一篇: IOS 改变图片尺寸和大小方法
下一篇: iOS反射机制: objc_property_t的使用
runtime666
博客等级 码龄10年 41粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值