dispatch_semaphoreの使用方法



How Use Dispatch_semaphore



Dispatch_semaphoreは、GCDが同期するための方法です。これに関連付けられている関数は、dispatch_semaphore_create、dispatch_semaphore_signal、dispatch_semaphore_waitの3つです。

以下に、3つの機能を1つずつ紹介します。



dispatch_semaphore_create

dispatch_semaphore_createの宣言は次のとおりです。



dispatch_semaphore_t dispatch_semaphore_create(long value)

渡された引数はlongであり、dispatch_semaphore_t型と値の値を持つセマフォを出力します。渡される引数の値は0以上である必要があることに注意してください。そうでない場合、dispatch_semaphore_createはNULLを返します。

dispatch_semaphore_signal

dispatch_semaphore_signalの宣言は次のとおりです。



long dispatch_semaphore_signal(dispatch_semaphore_t dsema)

この関数は、着信セマフォdsemaの値を1つインクリメントします。

dispatch_semaphore_wait

dispatch_semaphore_waitの宣言は次のとおりです。

long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);

この関数は、着信セマフォdsemaの値を1ずつデクリメントします。この関数の関数は、dsemaセマフォの値が0より大きい場合、関数が配置されているスレッドが次のステートメントとの値を実行し続けるようにします。セマフォdesemaの値が0の場合、この関数は現在のスレッドがタイムアウトを待機するのをブロックします(タイムアウトのタイプはdispatch_time_tであり、整数またはフロートタイプを直接渡すことはできません)。待機期間中のdesemの割合は、dispatch_semaphore_signal関数によってインクリメントされます。関数(つまり、dispatch_semaphore_wait)が配置されているスレッドがセマフォを取得すると、実行を継続し、セマフォを1つデクリメントします。待機期間中にセマフォが取得されなかった場合、またはセマフォの値が常に0の場合、タイムアウトに達すると、セマフォが含まれているスレッドが自動的に実行されます。

戻り値

dispatch_semaphore_signalの戻り値は長いです。戻り値が0の場合、スレッドの処理を待機しているセマフォがないことを意味します。処理されたセマフォの値が1増加します。戻り値が0でない場合、処理を待機しているセマフォ(1つ以上)スレッドが現在存在し、関数が待機中のスレッドをウェイクアップすることを示します(スレッドが優先度があり、最も優先度の高いスレッドがウェイクアップされます。それ以外の場合はランダムにウェイクアップされます)。
dispatch_semaphore_waitの戻り値も長いです。 0が返される場合は、関数が配置されているスレッドがタイムアウト前に正常に起動していることを意味します。戻り値が0でない場合は、タイムアウトが発生したことを意味します。

大きい

タイムアウトを設定するときは、DISPATCH_TIME_NOWとDISPATCH_TIME_FOREVERの2つのマクロが役立ちます。

DISPATCH_TIME_NOW indicates current DISPATCH_TIME_FOREVER represents a distant future

通常、タイムアウトをこれら2つのマクロのいずれかに設定するか、dispatch_time_tタイプの変数を自分で作成できます。タイプdispatch_time_tの変数を作成するには、dispatch_timeとdispatch_walltimeの2つの方法があります。これらの2つの変数は、dispatch_timeを作成してdispatch_time_t型変数を作成するときにも一般的に使用されます。

dispatch_timeの宣言は次のとおりです。

dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta);

タイプdispatch_time_tの変数とデルタ値を渡すために必要な場合のパラメーター。プラスデルタ時間がタイムアウト時間であることを示します。例えば:

dispatch_time_t t = dispatch_time(DISPATCH_TIME_NOW, 1*1000*1000*1000)

現在の時刻がタイムアウトのために1秒遅れていることを示します。

セマフォに関しては、一般的に駐車場を比喩として使用することが可能です。

駐車場には4台分の駐車スペースがありますので、4台同時に来ても停車できます。この時点で5台の車がある場合、1台は待たなければなりません。セマフォの値は、残りの駐車スペースの数に相当します。 dispatch_semaphore_wait関数は車と同等です。 dispatch_semaphore_signalは、車に乗るのと同じです。駐車スペースの残りの数は、初期化時に指定されています(dispatch_semaphore_create(long value))、
残りの駐車スペースが0の場合、dispatch_semaphore_signalを1回呼び出すと、残りの駐車スペースが1つ増え、dispatch_semaphore_waitの残りの駐車スペースが1つ減ります。複数の車を同時に駐車スペースで待機させることができます。一部の車の所有者は忍耐力がなく、自分で待ち時間を設定します。この間、彼らは駐車スペースが去るのを待ちません。彼らが待つならば、彼らは車で入って止まります。そして、何人かの所有者はここに車を駐車するのが好きなので、彼らは待つでしょう。

コードの簡単な例は次のとおりです。

dispatch_semaphore_t signal signal = dispatch_semaphore_create(1) __block long x = 0 NSLog(@'0_x:%ld',x) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(1) NSLog(@'waiting') x = dispatch_semaphore_signal(signal) NSLog(@'1_x:%ld',x) sleep(2) NSLog(@'waking') x = dispatch_semaphore_signal(signal) NSLog(@'2_x:%ld',x) }) // dispatch_time_t duration = dispatch_time(DISPATCH_TIME_NOW, 1*1000*1000*1000) //timeout 1 second // dispatch_semaphore_wait(signal, duration) x = dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER) NSLog(@'3_x:%ld',x) x = dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER) NSLog(@'wait 2') NSLog(@'4_x:%ld',x) x = dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER) NSLog(@'wait 3') NSLog(@'5_x:%ld',x) The final printed result is: 2017-08-11 22:51:54.734 LHTest[15700:70b] 0_x:0 2017-08-11 22:51:54.737 LHTest[15700:70b] 3_x:0 2017-08-11 22:51:55.738 LHTest[15700:f03] waiting 2017-08-11 22:51:55.739 LHTest[15700:70b] wait 2 2017-08-11 22:51:55.739 LHTest[15700:f03] 1_x:1 2017-08-11 22:51:55.739 LHTest[15700:70b] 4_x:0 2017-08-11 22:51:57.741 LHTest[15700:f03] waking 2017-08-11 22:51:57.742 LHTest[15700:f03] 2_x:1 2017-08-11 22:51:57.742 LHTest[15700:70b] wait 3 2017-08-11 22:51:57.742 LHTest[15700:70b] 5_x:0