当前位置:网站首页>Simple understanding of GCD
Simple understanding of GCD
2022-07-31 09:48:00 【kicinio】
一:基础名称
GCD的创建依赖于任务
与队列
这两个概念.
任务就是block内执行的操作,blockCall a method in.There are two ways to get the task,一为同步执行
,二为异步执行
.The difference between the two is whether have the ability to open the child thread,The way to perform tasks in the queue(顺序).
The characteristics of synchronous execution
同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行.
只能在当前线程中执行任务,不具备开启新线程的能力.
异步执行的特点:
异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务.
可以在新的线程中执行任务,具备开启新线程的能力.
可以看出,Synchronous execution must be specified in the current thread that executes,And asynchronous although have the ability to open the child thread,Specific also associated with the specified queue.
The structure of the queue is in the queue data structure,遵循先进先出的原则.The first task of a queue is appended to the queue,It should be completed first release.而GCDThere are two kinds of queue,一为串行队列
,二为并行队列
.The difference between the two of the location of the execution order and open the thread is not the same.
reservieren.The characteristics of serial queue:
“串”Is the task to perform the country on the current shaft,On a mission to complete,下一个任务开始执行.
只开启一个线程.
The characteristics of parallel queue:
Multiple tasks in the queue at the same time perform,是为“并发”.
Under the mode of asynchronous execution can open multiple threads execute simultaneously.
然而,在GCDInside there are two special queue,Is a serial queue主队列
,Belongs to the concurrent queue全局并发队列
.主队列属于串行队列,但是iOSThe program is in the home side column execution is created“主队列”的特殊.
1.1 dispatch_queue_t
This function is used to create a queue object,For serial queue,并发队列,主队列,串行队列
1.2 dispatch_group_t
This function is used to creategroup组队列
1.3 dispatch_group_async
The function based on the specified queue,去异步执行
1.4 dispatch_group_enter
This function marks a task appended to thegroup,执行一次,即groupDid not complete the task in the number of+1
1.5 dispatch_group_leave
This function marks a task has been completed,需要提醒groupTo remove a number of jobs,即groupDid not complete the task in the number of-1
1.6 dispatch_group_notify
当groupThe task for0时,会调用notify执行block,Often used to return to the main thread,The brokendispatch_group_wait
1.7 dispatch_semaphore_wait
This function makes the called thread lock,当semaphore信号量小于0时被阻塞
1.8 dispatch_semaphore_signal
This function is equivalent to be calling thread ends,会使得semaphore信号量+1
二: 排列方式
The table below for common arrangement
并发队列 | 串行队列 | 主队列 | |
---|---|---|---|
同步执行 | Did not open the child thread;串行执行任务 | Did not open the child thread;串行地执行任务 | 死锁 |
异步执行 | 开启了子线程;任务并行地执行 | 开启了子线程;串行执行任务 | Did not open the child thread;Task execution serially |
2.1 同步 + 并发队列
说明:
The composite can be carried in the current thread,不会开启新的线程,Because there is no ability to open the child thread synchronization execution.
Although the queue is specified for concurrent queue,But executive way for synchronous execution,Synchronous execution does not have the ability to open a thread,So the task only in a serial manner in the current thread one by one to perform.
Can determine the combination of the code execution order from top to bottom.
2.2 异步 + 并发队列
说明:
The portfolio will open a new thread.Since the asynchronous have the ability to open a new thread,The concurrent queue to determine the number of open a new thread.
Since the portfolio is asynchronous execution,The combination of(编写的方法)May exist in asynchronous execution queue before the code,This code can and asynchronous queue at the same time/交替执行.
2.3 同步 + 串行队列
说明:
The combination will not open new threads to perform,Because execution way is synchronous execution,This way does not have the ability to open a new thread;Serial queues and determines the number of threads only one,So the task will each perform.
该组合(方法)Performed within the code sequence from top to bottom,But complete progress depends on the complexity of the task itself(耗时性).
2.4 异步 + 串行队列
说明:
The portfolio will open a new thread,But will only open a.But as a result of serial queue queue is,So will only turn to perform these tasks in the open a new thread.
该组合(方法)Performed within the order from top to bottom.即,Combination of the new thread code and new threads execute simultaneously.
2.5 同步 + 主队列
说明:
If this combination in the form of a method directly in the main thread calls will cause a deadlock.The waiting inside the main thread method is done,The method processed task waiting inside the main thread,Both wait for each other,直接死锁.
But if in combination in the form of child thread calls,则不会发生死锁.原因即:The child thread wait for method performs to complete new open,And methods within the task is performed within the main thread,To finished the task within the main thread to perform,The child thread of new open also completed,也不会发生死锁.
2.6 异步 + 主队列
说明:
不会开启新的线程.Although asynchronous have the ability to open a new thread,But mainly queue queue,Only in this,So in the asynchronous task are in the home side column to perform.
The home team as a run on the main thread of the serial queue,任务挨个执行,The asynchronous tasks in this will each perform.
三:Common business scenarios and coding
3.1 Asynchronous thread communication
Asynchronous thread communication business scenario everywhere,The most common network request, for example,We usually open a child thread to request network,After the request to request data back to the main thread,For the main thread to refreshUI.
/** 线程间通信 - In the global concurrent queue mission,To the main thread after operation on data */
- (void)asyncDoAndAppendToMainQueue{
dispatch_queue_t global_concurrent_queue = dispatch_queue_create("DIS", DISPATCH_QUEUE_PRIORITY_DEFAULT);
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_async(global_concurrent_queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"------> THREAD: %@", [NSThread currentThread]);
NSInteger a = 1;
a++;
dispatch_async(main_queue, ^{
NSLog(@"------> value: %d", a);
NSLog(@"------> THREAD: %@", [NSThread currentThread]);
});
});
}
代码说明:Begin by creating a global queue,Then define a master queue.在dispatch_asyncFunction is introduced into the global queue to launch network request.In the simulated network request process,Take two seconds to makea++,And asynchronous back to the main line and print the data.结果如下:
2022-03-15 15:47:47.819016+0800 GCDios[17679:8316624] ------> THREAD: <NSThread: 0x2812ac380>{
number = 9, name = (null)}
2022-03-15 15:47:47.819246+0800 GCDios[17679:8316613] ------> value: 2
2022-03-15 15:47:47.819345+0800 GCDios[17679:8316613] ------> THREAD: <NSThread: 0x2812fc900>{
number = 1, name = main}
3.2 Asynchronous thread combination request and correction notice
有时候一个VCOr the module by not just a request,But several requests,How to pack several requests results for a unified callback parameter or object is a problem,Using a combination of the asynchronous request is a good way to solve(This business scenario because thisVCOr module is initialized when need more parameters or special model,And initialized only once,Can't be in the subsequent request refresh again).
/** Asynchronous execution global concurrent queue,enter leave后notify回到主线程 */
- (void)asyncDoGroupWithEnterLeaveAndAppendToMainQueue{
dispatch_queue_t global_concurrent_queue = dispatch_queue_create("DIS", DISPATCH_QUEUE_PRIORITY_DEFAULT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, global_concurrent_queue, ^{
NSInteger a = 0;
a++;
// 未完成任务数+1,标志着notify不会被调用
dispatch_group_enter(group);
[NSThread sleepForTimeInterval:2];
NSLog(@"------> value: %d", a);
NSLog(@"------> THREAD: %@\n", [NSThread currentThread]);
// The time-consuming task has been completed,应该从group队列里面移除
dispatch_group_leave(group);
// Again in a task togroup队列里
dispatch_group_enter(group);
[NSThread sleepForTimeInterval:2];
a++;
NSLog(@"------> value: %d", a);
NSLog(@"------> THREAD: %@\n", [NSThread currentThread]);
// 任务结束,从group立main移除,则会通知notify调用
dispatch_group_leave(group);
// 将groupQueue task manipulation of data back to the main thread
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"------> value: %d", a);
NSLog(@"------> THREAD: %@\n", [NSThread currentThread]);
});
});
}
可以看到,刚开始的时候groupThe task for0,然后调用dispatch_group_enter(group)
,使得该groupWithin the task number+1,而groupThe task for the0Under the condition of won't performdispatch_group_notify
方法的.When the first at the end of the simulation network request,调用dispatch_groyp_leave(group)
The task for-1In order to perform under a simulated network request.Stay after the second network request,groupThe task for0,Was performed at this timedispatch_group_notify
Way back to the main thread.If we are contained within the sample method ablock参数,并在notify内回调,The outer module will wait until after the all requests to get parameters or model.
结果如下:
2022-03-15 15:54:35.889857+0800 GCDios[17681:8317881] ------> value: 1
2022-03-15 15:54:35.890880+0800 GCDios[17681:8317881] ------> THREAD: <NSThread: 0x281fa0680>{
number = 8, name = (null)}
2022-03-15 15:54:37.896368+0800 GCDios[17681:8317881] ------> value: 2
2022-03-15 15:54:37.897212+0800 GCDios[17681:8317881] ------> THREAD: <NSThread: 0x281fa0680>{
number = 8, name = (null)}
2022-03-15 15:54:37.898013+0800 GCDios[17681:8317865] ------> value: 2
2022-03-15 15:54:37.898510+0800 GCDios[17681:8317865] ------> THREAD: <NSThread: 0x281ff02c0>{
number = 1, name = main}
3.3 异步任务通过dispatch_semaphore转同步
Sometimes the business to perform an asynchronous operations,But need the asynchronous operation results for the following code calls,This is an asynchronous task transfer synchronization task.
/** 异步任务通过semaphoreTurn to synchronize tasks */
- (void)asyncTransferSyncBySemaphore{
// 1. 当前为主线程
NSLog(@"------> currentThread: %@", [NSThread currentThread]);
// 2. To create a global queue to a child thread missions
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 3. 创建semaphore为0的信号量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// 4. 定义资源
__block NSInteger a = 20;
dispatch_async(queue, ^{
// 4.2 模拟耗时操作
[NSThread sleepForTimeInterval:2];
NSLog(@"------> Thread: %@", [NSThread currentThread]);
a++;
// 4.4 The main thread has been stuck at this time,执行这一步后semaphore+1,总和为0,主线程恢复
dispatch_semaphore_signal(semaphore);
});
// 4.1 The child thread synchronization with the main thread will execute,But the child thread and time-consuming operation has not yet been manipulating resourcesa,此时a为20
NSLog(@"------> Before wait Thread: %@ AND PARA A:%d", [NSThread currentThread], a);
// 4.3 信号量-1,主线程堵塞,As soon the child thread takes operation will complete,Followed by manipulating resourcesa,并使semaphore+1,Make the mainline Cheng Kaifang
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 4.5 After the main thread access resourcesaHave a quilt thread through lengthy operations control,此时a为21
NSLog(@"------> After wait Thread: %@ AND PARA A:%d", [NSThread currentThread], a);
}
如果最后一个LogStatements printing parametersa为21,That proves that we successfully transform the asynchronous task in order to synchronize tasks,And the following result is precisely illustrates this method.
结果如下:
2022-03-15 16:55:45.889530+0800 GCDios[17704:8329687] ------> currentThread: <NSThread: 0x2818ac900>{
number = 1, name = main}
2022-03-15 16:55:45.889676+0800 GCDios[17704:8329687] ------> Before wait Thread: <NSThread: 0x2818ac900>{
number = 1, name = main} AND PARA A:20
2022-03-15 16:55:47.894895+0800 GCDios[17704:8329702] ------> Thread: <NSThread: 0x2818e9f80>{
number = 6, name = (null)}
2022-03-15 16:55:47.895247+0800 GCDios[17704:8329687] ------> After wait Thread: <NSThread: 0x2818ac900>{
number = 1, name = main} AND PARA A:21
3.4 Asynchronous thread safety lock unlock
Competitive resource in a multithreaded when a change is never safe,May appear all sorts of strange question.在此,Simulate a common business,使用semaphoreSemaphore locking to ensure the safety of competitive resources.
At this point we have vehicles for20辆,Have two storesstore_1_queue与store_2_queue,Each store when customers booking vehicle makescarCount自减1,当carCount为0No longer provide booking service,Log没有车辆.
/// Simulation stores reserve a vehicle service
- (void)bookCar{
NSLog(@"------> FIRST: %@ AT THREAD: %@", self.semaphore, [NSThread currentThread]);
while (1) {
if (self.carCount > 0) {
self.carCount--;
NSLog(@"------> Store: %@, Used Count: %d", [NSThread currentThread], self.carCount);
[NSThread sleepForTimeInterval:0.2];
} else {
NSLog(@"------> Store: %@ has no car.", [NSThread currentThread]);
break;
}
}
}
上面使用了self.semaphore与self.carCount,在viewDidLoadMethod is not initialized in the can,如下:
self.carCount = 20;
self.semaphore = dispatch_semaphore_create(1);
Store code is as follows:
- (void)threadSafe{
// 创建门店1、门店2Serial queues to provide a way to buy
dispatch_queue_t store_1_queue = dispatch_queue_create("queue.dayueceng", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t store_2_queue = dispatch_queue_create("queue.changfenggongyuan", DISPATCH_QUEUE_SERIAL);
// 门店1Asynchronous execution ordering service
dispatch_async(store_1_queue, ^{
[self bookCar];
});
// 门店2Asynchronous execution ordering service
dispatch_async(store_2_queue, ^{
[self bookCar];
});
}
当在viewDidLoad内调用threadSafeMethod seems to be no problem,Every store in separate thread to performbookCar方法直至self.carCount为0然后Log没有车辆.But the problem is serious every store thread may at the same time to visitself.carCount,即会出现store_1_queueWhen booking number for16,And when the nextstore_2_queueWhen booking number for17,This is obviously not suture logic.因此需要使用semaphore信号量加锁,Made at the same time there is only one thread to visitself.carCount.完整代码如下:
@interface ViewController ()
@property (nonatomic, assign) NSInteger carCount;
@property (nonatomic, strong) dispatch_semaphore_t semaphore;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self initData];
[self threadSafe];
}
- (void)initData{
self.carCount = 20;
self.semaphore = dispatch_semaphore_create(1);
}
/** 线程安全示例 - Asynchronous access resources competition and update */
- (void)threadSafe{
// 创建门店1、门店2Serial queues to provide a way to buy
dispatch_queue_t store_1_queue = dispatch_queue_create("queue.dayueceng", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t store_2_queue = dispatch_queue_create("queue.changfenggongyuan", DISPATCH_QUEUE_SERIAL);
// 门店1Asynchronous execution ordering service
dispatch_async(store_1_queue, ^{
[self bookCar];
});
// 门店2Asynchronous execution ordering service
dispatch_async(store_2_queue, ^{
[self bookCar];
});
}
/// Simulation stores reserve a vehicle service
- (void)bookCar{
// For each store thread,The manipulation of the scheduled the same competition resourcesself.carCount,Just make sure there is only one thread at a time to visitself.carCountTo ensure the safety of thread
// 则使用wait与singalEnsure a store threads during the bookingsemaphoreAs the only visitor.
NSLog(@"------> FIRST: %@ AT THREAD: %@", self.semaphore, [NSThread currentThread]);
while (1) {
// 加锁,semaphore
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"------> WAIT: %@ AT THREAD: %@", self.semaphore, [NSThread currentThread]);
if (self.carCount > 0) {
self.carCount--;
NSLog(@"------> Store: %@, Used Count: %d", [NSThread currentThread], self.carCount);
[NSThread sleepForTimeInterval:0.2];
} else {
NSLog(@"------> Store: %@ has no car.", [NSThread currentThread]);
dispatch_semaphore_signal(self.semaphore);
break;
}
// 解锁
dispatch_semaphore_signal(self.semaphore);
NSLog(@"------> SIGNAL: %@ AT THREAD: %@", self.semaphore, [NSThread currentThread]);
}
}
Although can see every store threads accessbookCar方法,但是通过waitMake every store threads during the visit from加锁-Prevent other stores-This store-解锁
This process has been going,Until there is no vehicle available for scheduling.
结果如下:
2022-03-15 16:20:19.170210+0800 GCDios[17690:8322635] ------> FIRST: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:19.170332+0800 GCDios[17690:8322635] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:19.170381+0800 GCDios[17690:8322635] ------> Store: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}, Used Count: 19
2022-03-15 16:20:19.170467+0800 GCDios[17690:8322634] ------> FIRST: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:19.371599+0800 GCDios[17690:8322635] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:19.371779+0800 GCDios[17690:8322634] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:19.371850+0800 GCDios[17690:8322634] ------> Store: <NSThread: 0x280d84b00>{
number = 8, name = (null)}, Used Count: 18
2022-03-15 16:20:19.572499+0800 GCDios[17690:8322635] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:19.572502+0800 GCDios[17690:8322634] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:19.572929+0800 GCDios[17690:8322635] ------> Store: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}, Used Count: 17
2022-03-15 16:20:19.778504+0800 GCDios[17690:8322635] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:19.778827+0800 GCDios[17690:8322634] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:19.779001+0800 GCDios[17690:8322634] ------> Store: <NSThread: 0x280d84b00>{
number = 8, name = (null)}, Used Count: 16
2022-03-15 16:20:19.984579+0800 GCDios[17690:8322634] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:19.984587+0800 GCDios[17690:8322635] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:19.985258+0800 GCDios[17690:8322635] ------> Store: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}, Used Count: 15
2022-03-15 16:20:20.191370+0800 GCDios[17690:8322635] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:20.191516+0800 GCDios[17690:8322634] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:20.192384+0800 GCDios[17690:8322634] ------> Store: <NSThread: 0x280d84b00>{
number = 8, name = (null)}, Used Count: 14
2022-03-15 16:20:20.393759+0800 GCDios[17690:8322634] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:20.393768+0800 GCDios[17690:8322635] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:20.394415+0800 GCDios[17690:8322635] ------> Store: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}, Used Count: 13
2022-03-15 16:20:20.597513+0800 GCDios[17690:8322635] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:20.597750+0800 GCDios[17690:8322634] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:20.598420+0800 GCDios[17690:8322634] ------> Store: <NSThread: 0x280d84b00>{
number = 8, name = (null)}, Used Count: 12
2022-03-15 16:20:20.804358+0800 GCDios[17690:8322634] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:20.804525+0800 GCDios[17690:8322635] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:20.805148+0800 GCDios[17690:8322635] ------> Store: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}, Used Count: 11
2022-03-15 16:20:21.011005+0800 GCDios[17690:8322635] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:21.011204+0800 GCDios[17690:8322634] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:21.011824+0800 GCDios[17690:8322634] ------> Store: <NSThread: 0x280d84b00>{
number = 8, name = (null)}, Used Count: 10
2022-03-15 16:20:21.217719+0800 GCDios[17690:8322634] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:21.218465+0800 GCDios[17690:8322635] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:21.218938+0800 GCDios[17690:8322635] ------> Store: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}, Used Count: 9
2022-03-15 16:20:21.424744+0800 GCDios[17690:8322635] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:21.424779+0800 GCDios[17690:8322634] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:21.425369+0800 GCDios[17690:8322634] ------> Store: <NSThread: 0x280d84b00>{
number = 8, name = (null)}, Used Count: 8
2022-03-15 16:20:21.631025+0800 GCDios[17690:8322634] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:21.631465+0800 GCDios[17690:8322635] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:21.631723+0800 GCDios[17690:8322635] ------> Store: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}, Used Count: 7
2022-03-15 16:20:21.834804+0800 GCDios[17690:8322635] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:21.834888+0800 GCDios[17690:8322634] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:21.835452+0800 GCDios[17690:8322634] ------> Store: <NSThread: 0x280d84b00>{
number = 8, name = (null)}, Used Count: 6
2022-03-15 16:20:22.041551+0800 GCDios[17690:8322634] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:22.042263+0800 GCDios[17690:8322635] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:22.042735+0800 GCDios[17690:8322635] ------> Store: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}, Used Count: 5
2022-03-15 16:20:22.248610+0800 GCDios[17690:8322635] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:22.248646+0800 GCDios[17690:8322634] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:22.249263+0800 GCDios[17690:8322634] ------> Store: <NSThread: 0x280d84b00>{
number = 8, name = (null)}, Used Count: 4
2022-03-15 16:20:22.455297+0800 GCDios[17690:8322634] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:22.455332+0800 GCDios[17690:8322635] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:22.455917+0800 GCDios[17690:8322635] ------> Store: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}, Used Count: 3
2022-03-15 16:20:22.661461+0800 GCDios[17690:8322634] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:22.661466+0800 GCDios[17690:8322635] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:22.661857+0800 GCDios[17690:8322634] ------> Store: <NSThread: 0x280d84b00>{
number = 8, name = (null)}, Used Count: 2
2022-03-15 16:20:22.867473+0800 GCDios[17690:8322634] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:22.867513+0800 GCDios[17690:8322635] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:22.867893+0800 GCDios[17690:8322635] ------> Store: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}, Used Count: 1
2022-03-15 16:20:23.073678+0800 GCDios[17690:8322635] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:23.073685+0800 GCDios[17690:8322634] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:23.074345+0800 GCDios[17690:8322634] ------> Store: <NSThread: 0x280d84b00>{
number = 8, name = (null)}, Used Count: 0
2022-03-15 16:20:23.278227+0800 GCDios[17690:8322634] ------> SIGNAL: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:23.278236+0800 GCDios[17690:8322635] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d86ac0>{
number = 7, name = (null)}
2022-03-15 16:20:23.279220+0800 GCDios[17690:8322635] ------> Store: <NSThread: 0x280d86ac0>{
number = 7, name = (null)} has no car.
2022-03-15 16:20:23.280028+0800 GCDios[17690:8322634] ------> WAIT: <OS_dispatch_semaphore: 0x283bdf390> AT THREAD: <NSThread: 0x280d84b00>{
number = 8, name = (null)}
2022-03-15 16:20:23.280499+0800 GCDios[17690:8322634] ------> Store: <NSThread: 0x280d84b00>{
number = 8, name = (null)} has no car.
3.5 dispatch_barrier_async
Sometimes the business scenario first perform a set of asynchronous tasks,Then another group of asynchronous tasks.This time can be usedispoatch_barrier_asyncA fence split operation.
- (void)barrierAysnc{
dispatch_queue_t concurrent_queue = dispatch_queue_create("com.barrier", DISPATCH_QUEUE_CONCURRENT);
__block NSInteger a = 0;
dispatch_async(concurrent_queue, ^{
[NSThread sleepForTimeInterval:2];
a++;
NSLog(@"------> 1 CURRENT THREAD: %@", [NSThread currentThread]);
});
dispatch_async(concurrent_queue, ^{
[NSThread sleepForTimeInterval:2];
a++;
NSLog(@"------> 2 CURRENT THREAD: %@", [NSThread currentThread]);
});
dispatch_async(concurrent_queue, ^{
[NSThread sleepForTimeInterval:5];
a++;
NSLog(@"------> 3 CURRENT THREAD: %@", [NSThread currentThread]);
});
dispatch_barrier_sync(concurrent_queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"------> value:%ld barrier CURRENT THREAD: %@", (long)a, [NSThread currentThread]);
});
dispatch_async(concurrent_queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"------> 4 CURRENT THREAD: %@", [NSThread currentThread]);
});
dispatch_async(concurrent_queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"------> 5 CURRENT THREAD: %@", [NSThread currentThread]);
});
}
在dispatch_barrier_async
执行之前,To open a child of the line layer is operating resources(a)进行操作,dispatch_barrier_async
执行的时候,Make use of resources for further operation; reservieren.The process to complete,Will perform a second group of asynchronous operations.
结果如下:
2022-03-21 15:28:08.445063+0800 GCDios[18226:9521504] ------> 1 CURRENT THREAD: <NSThread: 0x2838c0140>{
number = 5, name = (null)}
2022-03-21 15:28:08.445146+0800 GCDios[18226:9521499] ------> 2 CURRENT THREAD: <NSThread: 0x2838c0d40>{
number = 6, name = (null)}
2022-03-21 15:28:11.445473+0800 GCDios[18226:9521503] ------> 3 CURRENT THREAD: <NSThread: 0x2838c0b80>{
number = 7, name = (null)}
2022-03-21 15:28:13.447573+0800 GCDios[18226:9521489] ------> value:3 barrier CURRENT THREAD: <NSThread: 0x2838808c0>{
number = 1, name = main}
2022-03-21 15:28:15.452746+0800 GCDios[18226:9521503] ------> 4 CURRENT THREAD: <NSThread: 0x2838c0b80>{
number = 7, name = (null)}
2022-03-21 15:28:15.452800+0800 GCDios[18226:9521499] ------> 5 CURRENT THREAD: <NSThread: 0x2838c0d40>{
number = 6, name = (null)}
四:dispatch_semaphore浅谈
4.1 dispatch_semaphore_t
dispatch_semaphore_t
用来声明dispatch_semaphore函数,Create the usedispatch_semaphore_create
函数,The function relies on the structdispatch_semaphore_s,The latter structure declaration as follows:
struct dispatch_semaphore_s {
DISPATCH_STRUCT_HEADER(semaphore);
semaphore_t dsema_port; //等同于mach_port_t信号
long dsema_orig; //Initialization signal value
long volatile dsema_value; //当前信号量值
union {
long volatile dsema_sent_ksignals;
long volatile dsema_group_waiters;
};
struct dispatch_continuation_s *volatile dsema_notify_head; //notify的链表头部
struct dispatch_continuation_s *volatile dsema_notify_tail; //notify的链表尾部
};
dispatch_semaphore_createInside the function is used when applying to addressdispatch_semaphore_s结构体,其dsma变量会根据dispatch_semaphoreCalculate the appropriate space.dispatcH-semaphore_tThe function of internal as follows:
dispatch_semaphore_t dispatch_semaphore_create(long value) {
dispatch_semaphore_t dsema;
if (value < 0) {
//valueValue should be greater than or equal to0
return NULL;
}
//申请dispatch_semaphore_t的内存
dsema = (dispatch_semaphore_t)_dispatch_alloc(DISPATCH_VTABLE(semaphore),
sizeof(struct dispatch_semaphore_s) -
sizeof(dsema->dsema_notify_head) -
sizeof(dsema->dsema_notify_tail));
//调用初始化函数
_dispatch_semaphore_init(value, dsema);
return dsema;
}
//初始化结构体信息
static void _dispatch_semaphore_init(long value, dispatch_object_t dou) {
dispatch_semaphore_t dsema = dou._dsema;
dsema->do_next = (dispatch_semaphore_t)DISPATCH_OBJECT_LISTLESS;
dsema->do_targetq = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dsema->dsema_value = value; //Set the signal currentvalue值
dsema->dsema_orig = value; //Set the signal of the initialvalue值
}
从这里我们可以看到,当调用dispatch_semaphore_create()
函数时,If the initial value is less than1则会返回空,这是我们需要注意的地方.And the other a place need to be aware of asdispatch_semaphore
销毁的时候.Destroyed when the function is as follows:
//释放信号量的函数
void _dispatch_semaphore_dispose(dispatch_object_t dou) {
dispatch_semaphore_t dsema = dou._dsema;
if (dsema->dsema_value < dsema->dsema_orig) {
//Warning:The signal is still in use when the destruction will crash
DISPATCH_CLIENT_CRASH(
"Semaphore/group object deallocated while in use");
}
kern_return_t kr;
if (dsema->dsema_port) {
kr = semaphore_destroy(mach_task_self(), dsema->dsema_port);
DISPATCH_SEMAPHORE_VERIFY_KR(kr);
}
}
可以看到,If the signal value is less than the initial value will collapse,Therefore must careful attention to the Settingsdispatch_semaphoreThe value in the semaphore while they are still in use do not set it asnil或重新赋值.
4.2 dispatch_semaphore_wait
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout){
long value = dispatch_atomic_dec2o(dsema, dsema_value, acquire);
if (fastpath(value >= 0)) {
return 0;
}
return _dispatch_semaphore_wait_slow(dsema, timeout);
}
dispatch_semaphore_wait
First the semaphoredsemaAtomic value minus one,And to assign a new value tovalue.如果value大于等于0就立即返回,否则调用_dispatch_semaphore_wait_slow
函数,Waiting for a semaphore sensei ortimeout超时._dispatch_semaphore_wait_slow
The realization of the function is more complicated,这里不再展开赘述.
4.3 dispatch_semaphore_signal
long dispatch_semaphore_signal(dispatch_semaphore_t dsema) {
long value = dispatch_atomic_inc2o(dsema, dsema_value, release);
if (fastpath(value > 0)) {
return 0;
}
if (slowpath(value == LONG_MIN)) {
DISPATCH_CLIENT_CRASH("Unbalanced call to dispatch_semaphore_signal()");
}
return _dispatch_semaphore_signal_slow(dsema);
}
首先将dsema_valueCall atom method and1,If greater than zero return immediately0,否则进入_dispatch_semaphore_signal_slow
函数,该函数会调用semaphore_signal
Function aroused indispatch_semaphore_wait
中等待的线程._dispatch_semaphore_signal_slow
同样不再赘述.
五:dispatch_group浅谈
dispatch_group
The creation of is, in fact, depend ondispatch_semaphore
,Here are commonly used function to discuss.
5.1 dispatch_group_create
dispatch_group_t dispatch_group_create(void) {
return (dispatch_group_t)dispatch_semaphore_create(LONG_MAX);
}
可以看到,dispatch_group_create
Is the creation of inLONG_MAX
For a semaphoredispatch_semaphore,As for why semaphore asLONG_MAX
,Speculation is likely to be in order to prevent the user too much calls and collapse dispatch semaphore specially big.
5.2 dispatch_group_enter
void dispatch_group_enter(dispatch_group_t dg) {
dispatch_semaphore_t dsema = (dispatch_semaphore_t)dg;
(void)dispatch_semaphore_wait(dsema, DISPATCH_TIME_FOREVER);
}
可以看到,dispatch_group实际上就是以当前group为参数,发出wait信号量.
5.3 dispatch_group_leave
void dispatch_group_leave(dispatch_group_t dg) {
dispatch_semaphore_t dsema = (dispatch_semaphore_t)dg;
dispatch_atomic_release_barrier();
long value = dispatch_atomic_inc2o(dsema, dsema_value);
//dsema_value原子性加1
if (slowpath(value == LONG_MIN)) {
//内存溢出,由于dispatch_group_leave在dispatch_group_enter之前调用
DISPATCH_CLIENT_CRASH("Unbalanced call to dispatch_group_leave()");
}
if (slowpath(value == dsema->dsema_orig)) {
//表示所有任务已经完成,唤醒group
(void)_dispatch_group_wake(dsema);
}
}
可以看到 dispatch_group_leave
将 dispatch_group_t
转换成 dispatch_semaphore_t
后将 dsema_value Add the value of the atomic1.如果 value 为 LONG_MIN 则崩溃;如果 value 等于 dsema_orig Said all the tasks completed,调用 _dispatch_group_wake
唤醒group(即唤醒notify函数)
边栏推荐
- 模块八
- The future of the hybrid interface: conversational UI
- JS中原型和原型链的详细讲解(附代码示例)以及 new关键字具体做了什么的详细讲解
- Rich text editor Tinymce
- js right dot single page scrolling introduction page
- What is the encoding that starts with ?
- MySQL----多表查询
- 如何将虚拟机上的文件复制到主机上
- Flink1.15源码阅读flink-clients——flink命令行帮助命令
- js radar chart statistical chart plugin
猜你喜欢
随机推荐
Build finished with errors/Executable Not Found
使用turtle画按钮
Day113.尚医通:用户认证、阿里云OSS、就诊人管理
Implement a thread pool
matlab常用符号用法总结
二叉树的搜索与回溯问题(leetcode)
Dart Log工具类
第二十二课,实例化(instancing)
【软考软件评测师】2012综合知识历年真题
OpenGL es 初识
UE4插件软链接(关联)
spark filter
JSP exception对象简介说明
MySQL 的几种碎片整理方案总结(解决delete大量数据后空间不释放的问题)
Scala basics [seq, set, map, tuple, WordCount, queue, parallel]
作为面试官,关于线程池的问题我一般这样套路...
postgresql 生成随机日期,随机时间
数字加分隔符
Chapter VII
零代码工具推荐 八爪鱼采集器