GCDアプリケーション分析
1、dispatch_group_t组
GCDのスレッド同期
たとえば、次のように複数の同時のネットワーク要求(例:タスク1、タスク2)、などいくつかのタスクを、行うために、各希望がしかし、タスクが完了した後、このシナリオでは、次のタスクを実行する、最も一般的にはGCDでありますグループ
1、dispatch_group_async
チームタスク1、タスク2、タスク1に加えdispatch_group_async()によってはdispatch_group_notify()によってその後実行され、タスク2は、タスクの終了後に引き継ぎます。
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, globalQueue, ^{
sleep(1);
NSLog(@"task 1");
});
dispatch_group_async(group, globalQueue, ^{
sleep(1);
NSLog(@"task 2");
});
//全部执行完毕
dispatch_group_notify(group, globalQueue, ^{
NSLog(@"task done");
});
2は、グループおよびグループに
グループへ:dispatch_group_enter()、(入力)のキューにタスクを追加するグループを告げる
グループ:dispatch_group_leave()、(休暇)タスクの実行が終わったグループを伝え、それが取り除かグループで
待機:dispatch_group_wait ()、ブロックを現在のスレッド、休暇の等しい数(待機)と時間よりも倍以上の数を入力し、実装をダウン続けます。
コンプリート:dispatch_group_notify()、同じ回数及び(通知)休暇を入力して、タスクを実行します。
従って(dispatch_group_leave)とペアで使用するdispatch_group_wait()
要求は、タスク12の後、タスクを実行するために必要であれば、以下のように上記の例では、修正されてもよいです。
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), globalQueue, ^{
//// sleep(1);
// NSLog(@"task 1");
// dispatch_group_leave(group);
// });
dispatch_async(globalQueue, ^{
sleep(2);
NSLog(@"task 1");
dispatch_group_leave(group);
});
//永远等待,也就是当任务1不出组(移出),当前线程就永远等待。
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_group_enter(group);
dispatch_async(globalQueue, ^{
NSLog(@"task 2");
dispatch_group_leave(group);
});
// NSLog(@"task 2");
// dispatch_group_leave(group);
//全部执行完毕。非线程阻塞
dispatch_group_notify(group, globalQueue, ^{
NSLog(@"task done");
});
NSLog(@"是否阻塞?");
dispatch_group_notify機能は、スレッド、dispatch_group_waitブロックスレッドをブロックしません。
dispatch_group_notify機能がタスクに直接追加することができ、単純にスレッドをブロックdispatch_group_wait機能は、それが独自の個別追加「サマリータスク」必要があり、下向き続け
dispatch_group_asyncキューが同じキューであるかどうかのパラメータキューdispatch_group_notify機能を、実行を持続させます
2、dispatch_barrier_async
閉塞は、同期および非同期のブロッキング
2は、dispatch_barrier_async妨げる
など(グローバルかどうかなど、他のキューが、)dispatch_queue_create同時キューによって作成された場合、クラスキューAPIの部門(のためにのみ有効である)をdispatch_barrier_async / dispatch_barrier_syncなり、dispatch_queue_create DISPATCH_QUEUE_CONCURRENT(同時)によって作成されましたdispatch_async / dispatch_sync、失われた特殊性、そのdispatch_barrier_asyncの効果なし「フェンス」。
dispatch_queue_t queue = dispatch_queue_create("com.liujilou.barrier", DISPATCH_QUEUE_CONCURRENT);
__block int a = 10;
dispatch_async(queue, ^{
NSLog(@"读取1 a=%d",a);
});
dispatch_async(queue, ^{
NSLog(@"读取2 a=%d",a);
});
dispatch_async(queue, ^{
NSLog(@"读取3 a=%d",a);
});
//
dispatch_barrier_async(queue, ^{
sleep(1);
NSLog(@"赋值 a=%d",a);
a = 20;
});
NSLog(@"主线程执行");
dispatch_async(queue, ^{
NSLog(@"读取4 a=%d",a);
});
dispatch_async(queue, ^{
NSLog(@"读取5 a=%d",a);
});
/*
2020-03-15 15:16:21.510753+0800 filedome[73509:2023353] 主线程执行
2020-03-15 15:16:21.510763+0800 filedome[73509:2023414] 读取1 a=10
2020-03-15 15:16:21.510781+0800 filedome[73509:2023415] 读取2 a=10
2020-03-15 15:16:21.510783+0800 filedome[73509:2023416] 读取3 a=10
2020-03-15 15:16:22.515361+0800 filedome[73509:2023416] 赋值 a=10
2020-03-15 15:16:22.515739+0800 filedome[73509:2023415] 读取5 a=20
2020-03-15 15:16:22.515736+0800 filedome[73509:2023416] 读取4 a=20
*/
分析が示す印刷結果により、(1-3読み取り)前dispatch_barrier_async同時実行タスクキューに追加され、タスクは、これらのタスクの実行が完了した後dispatch_barrier_asyncで行われます。一方dispatch_barrier_asyncは、現在のスレッドをブロックします、我々は、直線zはこれらの後ろに続けるためにしたタスクを完了する必要がありますが、メインスレッドをブロックすることはありません、メインスレッドが適切に実行することができます。タスクを実行すると、同時実行の後ろに続きます。
図dispatch_barrier_async.png
dispatch_barrier_syncは、メインスレッドをブロックします。
3、dispatch_suspend()和dispatch_resume()
サスペンド、レジュームキュー
dispatch_suspend(キュー)は、保留キュー(ローカル過度の操作を実行する必要はありませんとは、キューを一時停止した後、キューを復元)指定された;
dispatch_resume(キュー)再開実行キューは、
処理が行われた影響はありません。、保留キューに追加した後、実装されていないタスクが回復するまで中断されます。回復プロセスが継続した後。
dispatch_suspendはすぐにブロックの実行を中断しませんが、現在のブロックの実行が完了した後、実行ブロックのその後のサスペンション。
ペアで、かどうかのエラーで使用されます。
4、dispatch_semaphore_createセマフォ
信号セマフォは> = 1時間であり、それらが許可されていないかどうかを、可能にします。マルチスレッド用のロック機構。
// 1、创建信号量为1
dispatch_semaphore_t semaphoer = dispatch_semaphore_create(1);
// 2、等待 加锁
// 第一个参数 信号量。信号量 >=1 的时候允许通过。并对其进行 减1操作。
// 等待 第二个参数等待时间,这里用一个未来的时间也就是一直等待。
dispatch_semaphore_wait(semaphoer, DISPATCH_TIME_FOREVER);
// 3、解锁
// 计数加1,相当于解锁。在任务执行完可以再次访问的时候进行加1 解锁
dispatch_semaphore_signal(sem);
// 这三个步骤必须都有,否者会崩溃。
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
// 计数 减 1
long result = dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
if (result == 0) {
NSLog(@"task 1");
// 计数 加 1
dispatch_semaphore_signal(sem);
}else{
// 计数不为0的情况进行处理
NSLog(@"task 2");
}
dispatch_queue_t queue = dispatch_queue_create(0, 0);
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
dispatch_async(queue, ^{
for (int i=0; i<10000; i++) {
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
self.num++;
dispatch_semaphore_signal(sem);
NSLog(@"%d",self.num);
}
});
dispatch_async(queue, ^{
for (int i=0; i<10000; i++) {
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
self.num++;
dispatch_semaphore_signal(sem);
NSLog(@"%d",self.num);
}
});
// 这样就能打印到20000,如果不加锁中间可能会有同时访问拿到同样的值进行操作,这样得到的最终结果就不一定是20000,线程安全。
// 同时信号量也能控制开辟线程的数量,例如上面的代码我们可以设置信号量为2。可以开辟2个线程进行处理。
インタビューの質問の分析
1、
dispatch_queue_t queue = dispatch_queue_create("liujilou", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
// NSLog(@"4");
});
NSLog(@"5");
デッドロック。152は、通常の印刷を行います。次は、同期ワードが実行するスレッドをブロックします、同期です。しかし、このシンクブロックの後ろにプットが実行アイソクロナスブロック3.4、タスクを持っているブロック3を実行する必要が続き、4で、タスク追加のチームが3を行ってきました。図3は、ブロックが実行ブロックを完了しましたです。それは同期シリアルであるため、FIFO原則の必要性が、4ブロックが実行されるまで待機実行される3つのニーズをブロックするので、新しいスレッドを開いたが、彼らはデッドロックを起こし、4 3実行を待つ必要はありません。
でも4人のタスクの遺骨がデッドロックコメントしました。同期機能は、最初のキューに追加するので、なぜ内部、タスク3がキューに追加されます。タスク3を実行するには、同期機能を実行するまで待機する必要がありますが、同期機能が実行を実行する3考慮する必要があるタスクが完了しています。彼らは互いの待機を形成しています。
2、
dispatch_queue_t queue = dispatch_queue_create("liujilou", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
/*
2020-03-14 01:18:15.206466+0800 filedome[59905:1360188] 1
2020-03-14 01:18:15.206720+0800 filedome[59905:1360188] 5
2020-03-14 01:18:15.206845+0800 filedome[59905:1360270] 2
2020-03-14 01:18:15.206947+0800 filedome[59905:1360270] 3
2020-03-14 01:18:15.207040+0800 filedome[59905:1360270] 4
*/
コードはまた、第5に時間がかかるが実行され、その後、非同期関数は、スレッドをブロックしない、上から下の順序の実行にコンパイル1を実行し、次いで2を実行します。次のスレッドが、4を実行するために3を実行しなければならない同期ブロックです。
3、
dispatch_queue_t queue = dispatch_queue_create("liujilou", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_async(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
/*
2020-03-14 01:19:52.246409+0800 filedome[59934:1361575] 1
2020-03-14 01:19:52.246576+0800 filedome[59934:1361575] 5
2020-03-14 01:19:52.246611+0800 filedome[59934:1361843] 2
2020-03-14 01:19:52.246703+0800 filedome[59934:1361843] 4
2020-03-14 01:19:52.246717+0800 filedome[59934:1361634] 3
*/
コードはまた、第5に時間がかかるが実行され、その後、非同期関数は、スレッドをブロックしない、上から下の順序の実行にコンパイル1を実行し、次いで2を実行します。次は、最初の4つ、次いで3の実装行う非同期共感で
、4
dispatch_queue_t queue = dispatch_queue_create("com.liujilou.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"1");
});
dispatch_async(queue, ^{
NSLog(@"2");
});
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"0");
dispatch_async(queue, ^{
NSLog(@"7");
});
dispatch_async(queue, ^{
NSLog(@"8");
});
dispatch_async(queue, ^{
NSLog(@"9");
});
/*
2020-03-14 01:27:51.772658+0800 filedome[60051:1366298] 3
2020-03-14 01:27:51.772671+0800 filedome[60051:1366397] 1
2020-03-14 01:27:51.772676+0800 filedome[60051:1366395] 2
2020-03-14 01:27:51.772784+0800 filedome[60051:1366298] 0
2020-03-14 01:27:51.772906+0800 filedome[60051:1366396] 9
2020-03-14 01:27:51.772889+0800 filedome[60051:1366395] 7
2020-03-14 01:27:51.772920+0800 filedome[60051:1366397] 8
*/
結果は、より多くのであるが、固定されているためのいくつかの値が存在します。3は、3 0のバックが実行を実行する前に、後者の3つの非同期実行は次いで終了0を待機する待機するように同期されます。
123は、三、30固定シーケンスの順に限りません。789順序は必ずしもないが、確か後0。そして、より多くの限り、これらの条件が満たされている通り正しいです。