web-dev-qa-db-ja.com

swift

複数のスレッド間で共有メモリを使用しています。これらのスレッドが同時にこのメモリにアクセスするのを防ぎたいのですが。 ((producer-consumerproblemのように)

問題

スレッドが要素をキューに追加し、別のスレッドがこれらの要素を読み取って削除します。彼らは同時にキューにアクセスすべきではありません。

この問題の解決策の1つは、Mutexを使用することです。

私が見つけたように、Swiftにはミューテックスがありません。 Swiftに代替手段はありますか?

20
rick

人々が私を含めてコメントしたように、この種のロックを達成するにはいくつかの方法があります。しかし、ディスパッチセマフォはオーバーヘッドが最も少ないと思われるため、他のものより優れていると思います。 Apples doc、 "Replacing Semaphore Code" で見られるように、セマフォがすでにロックされている(= 0)場合を除いて、カーネルスペースには移動しません。スレッドを切り替えるカーネル。ほとんどの場合、セマフォはゼロではないと思います(もちろん、これはアプリ固有の問題です)。したがって、多くのオーバーヘッドを回避できます。

上記とは逆のシナリオであるディスパッチセマフォに関するもう1つのコメント。スレッドの実行優先度が異なり、優先度の高いスレッドがセマフォを長時間ロックする必要がある場合、セマフォのディスパッチは解決策にならない可能性があります。これは、待機中のスレッド間に「キュー」がないためです。この場合に発生するのは、優先度の高いスレッドがほとんどの時間セマフォを取得してロックし、優先度の低いスレッドはセマフォをたまにしかロックできないため、ほとんどが待機しているだけです。この動作がアプリケーションにとって適切でない場合は、代わりにディスパッチキューを検討する必要があります。

3
beshio

これには多くの解決策がありますが、この種のアクションにはシリアルキューを使用します。

let serialQueue = DispatchQueue(label: "queuename")
serialQueue.sync { 
    //call some code here, I pass here a closure from a method
}

編集/更新:セマフォの場合:

let higherPriority = DispatchQueue.global(qos: .userInitiated)
let lowerPriority = DispatchQueue.global(qos: .utility)

let semaphore = DispatchSemaphore(value: 1)

func letUsPrint(queue: DispatchQueue, symbol: String) {
    queue.async {
        debugPrint("\(symbol) -- waiting")
        semaphore.wait()  // requesting the resource

        for i in 0...10 {
            print(symbol, i)
        }

        debugPrint("\(symbol) -- signal")
        semaphore.signal() // releasing the resource
    }
}

letUsPrint(queue: lowerPriority, symbol: "Low Priority Queue Work")
letUsPrint(queue: higherPriority, symbol: "High Priority Queue Work")

RunLoop.main.run()
8
Devanshu Saini

beshio のコメントのおかげで、次のようにセマフォを使用できます。

let semaphore = DispatchSemaphore(value: 1)

リソースを使用する前に待機を使用します。

semaphore.wait()
// use the resource

そしてrelease itを使用した後:

semaphore.signal()

各スレッドでこれを行います。

6
A.bee