わかりやすいDispatchSemaphore

2080 ワード

DispatchSemaphore


信号量は、同時アクセスリソースを制御するためのメカニズムであり、マルチスレッドに多く用いられ、同時スレッド数を制御することができる.

  • 第1例
  • let queue = DispatchQueue.global()
    var arr = [Int]()
    for i in 0..<10000 {
        queue.async {
            print("add \(i)")
            arr.append(i)
        }
    }
    

    実行結果:一定時間実行後、プログラムcrash crash原因分析:Arrayはスレッドが安全ではなく、マルチスレッドが同時にArrayを操作してcrashを招く
  • 第2例
  • let semaphore = DispatchSemaphore(value: 1)
    let queue = DispatchQueue.global()
    var arr = [Int]()
    for i in 0..<10000 {
        queue.async {
            if semaphore.wait(timeout: .distantFuture) == .success {
                print("add \(i)")
                arr.append(i)
                semaphore.signal()
            }
        }
    }
    

    運転結果:正常に動作し、arrにデータが正常に追加されました注意:arrのデータは0~9999という順序で厳密に追加されたものではありません

    例解析

  • 信号量
  • を作成する.
    let semaphore = DispatchSemaphore(value: 1)
    

    valueは初期値を表し、ここでは1の別の解釈に設定します.WCには穴が1つしかありません.
  • 待機信号量
  • if semaphore.wait(timeout: .distantFuture) == .success
    
    semaphoreの値が0でない場合、上記の関数はsuccessを返し、semaphoreの値を1減少させる.0の場合、スレッドはtimeoutまで待機します(関数は返されず、次のコードは実行されません).timeoutは待ち時間の最大時間を制御することができ、.distantFutureは永久待ち時間を表すように設定される.
    もう一つの解釈:一人の客が来て、もし穴があれば、占めて、穴の数-1、さもなくば前の客が使い終わって離れるのを待っています
  • 送信信号量
  • semaphore.signal()
    
    semaphoreの値+1を、この時点で他の待機中のスレッドが起動されて実行される(同じ優先度でランダムに起動する)別の解釈:お客様が使用済みになって離れ、ピット数+1

    まとめてみる

  • コードに設定信号量の初期値は1
  • である.
  • 第1サイクル、waitsuccessを返し、if文内のコードを実行するとともに、信号量が0に減少するより厳密にはqueue中の非同期taskが最初に実行されたとき、第1のtaskは必ずしも第1サイクルで追加するその
  • ではないからである.
  • は、信号量が0であるため、スレッドが待機(第1サイクルif内のコードがまだ実行されていないと仮定する)し、後のサイクルは
  • に類似する.
  • 第1サイクルif文内のsemaphore.signal()コードが実行されると、信号量の値は1となり、1となる.したがって、現在待機中のスレッドのいずれかが起動して実行され、他のスレッドは
  • を待機し続ける.
  • 順次類推...

  • 以上、もし問題があれば、指摘を歓迎して、感謝しきれません...