C言語でGrand Central Dispatch(GCD)を使ってみた(その1)

# 本記事について
macOS、iOS、watchOS、tvOSのマルチコアハードウェアにおいて配列でタスクを実行させるための技術、Grand Central Dispatch(GCD)の理解を深めるため、敢えてC言語縛りで使ってみました。
　<font color="Blue">(嘘です…本当はまだObject-CやSwiftをあまり使ったことがないからです…)</font>

# 実行環境
・macOS Ventura 13.0.1
・Apple clang version 14.0.0 (clang-1400.0.29.202)　
・lldb-1400.0.38.17
・MacBook Pro 13インチ M2
　<font color="Red">※Homebrew GCCは使えなかったです…</font>

# サンプルソース
5秒周期でログを10回出力するソースです。
```cpp
  1 #include <dispatch/dispatch.h>
  2 #include <stdio.h>
  3 #include <Block.h>
  4 
  5 int main(void)
  6 {
  7         __block int i = 0;
  8         
  9         dispatch_queue_t queue;
 10         dispatch_source_t source;
 11         dispatch_time_t start_time;
 12         
 13         /*　新規ディスパッチキューを作成　*/
 14         queue = dispatch_queue_create("jp.test_queue", DISPATCH_QUEUE_SERIAL);
 15         
 16         /*　タイマーのディスパッチソースを生成　*/
 17         source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
 18         
 19         /*　イベント発生後に呼ばれるブロックを設定　*/
 20         dispatch_source_set_event_handler(source, ^{
 21                 printf("5秒後に起動。%d番目。\n", i);
 22                 i++; 
 23                 if(i == 10){
 24                         printf("実行停止。\n");
 25                         dispatch_suspend(source);
 26                         dispatch_source_cancel(source);
 27                 
 28                         exit(0);
 29                 }
 30         });
 31         
 32         /*　タイマーを設定　*/
 33         start_time = dispatch_time(DISPATCH_TIME_NOW, 0);
 34         dispatch_source_set_timer(source, start_time, 5.0*NSEC_PER_SEC, 0);
 35         
 36         /*　中断されている新規ディスパッチキューを再開　*/
 37         printf("実行開始！\n");
 38         dispatch_resume(source);
 39         
 40         /*　新規ディスパッチキューを実行させるため、メインスレッドを停止　*/
 41         dispatch_main();
 42         
 43         return 0;
 44 }
```
# 実行結果　
```
実行開始！
5秒後に起動。0番目。
5秒後に起動。1番目。
5秒後に起動。2番目。
5秒後に起動。3番目。
5秒後に起動。4番目。
5秒後に起動。5番目。
5秒後に起動。6番目。
5秒後に起動。7番目。
5秒後に起動。8番目。
5秒後に起動。9番目。
実行停止。
```
# 自分なりの解釈　
まず、下記の<font color="red">関数dispatch_queue_create()</font>にて、<font color="blue">**新規のディスパッチキューを作成します。**</font>
第二引数に<font color="green">DISPATCH_QUEUE_SERIAL</font>を指定することにより、<font color="blue">シリアルにFIFO 順でブロックを実行するディスパッチキュー</font>にすることが出来ます。

```cpp
 12         
 13         /*　新規ディスパッチキューを作成　*/
 14         queue = dispatch_queue_create("jp.test_queue", DISPATCH_QUEUE_SERIAL);
 15  
```
次に、下記の<font color="red">関数dispatch_source_create()</font>で、第一引数に<font color="green">DISPATCH _SOURCE_TIMER </font>を指定することにより、<font color="blue">タイマーに基づいて、新規ディスパッチキューqueueにイベントハンドラブロックを提出する**ディスパッチソース**</font>を作成します。
```cpp
 15         
 16         /*　タイマーのディスパッチソースを生成　*/
 17         source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
 18 
```
ただ、これだけだと
<font color="blue">**①タイマーの周期はまだ不明瞭。
②タイマー満了後に新規ディスパッチキューに提出されるイベントハンドラブロックは？？？**</font>
という状態になってしまうので、<font color="red">**最低でも更に２種類の関数を使用する必要があります。**</font>

まずは、<font color="red">関数dispatch_source_set_event_handler(）</font>にて、<font color="blue">ディスパッチキューに提出されるイベントハンドラブロックを定義します。</font>
(5秒周期のタイマー満了後にメッセージを10回出力。
メッセージを10回出力した後は、そのディスパッチソースを中断・キャンセルし、そのまま終了するという処理を実装。)
```cpp
 19         /*　イベント発生後に呼ばれるブロックを設定　*/
 20         dispatch_source_set_event_handler(source, ^{
 21                 printf("5秒後に起動。%d番目。\n", i);
 22                 i++; 
 23                 if(i == 10){
 24                         printf("実行停止。\n");
 25                         dispatch_suspend(source);
 26                         dispatch_source_cancel(source);
 27                 
 28                         exit(0);
 29                 }
 30         });
```
この後、<font color="red">関数dispatch_source_set_timer()</font>にて、<font color="blue">そのタイマーのディスパッチソースのタイマー開始時刻や間隔などを定義します。</font>
(今回はすぐに5秒間隔のタイマー起動という感じに設定しときます。）
```cpp
 31         
 32         /*　タイマーを設定　*/
 33         start_time = dispatch_time(DISPATCH_TIME_NOW, 0);
 34         dispatch_source_set_timer(source, start_time, 5.0*NSEC_PER_SEC, 0);
 35  
```

これであらかたのコーディングは終了なのですが、最後に忘れてはならないのが<font color="red">**関数dispatch_resume()**</font>です！！！
<font color="blue">**新規ディスパッチソースは作った段階ではsuspend状態ですので、resumeで発動させなければいけません。**</font>
```cpp
 36         /*　中断されている新規ディスパッチキューを再開　*/
 37         printf("実行開始！\n");
 38         dispatch_resume(source);
 39         
 40         /*　新規ディスパッチキューを実行させるため、メインスレッドを停止　*/
 41         dispatch_main();
```