21343


複数のスレッドから扱うメモリーデータをアクセスする場合に排他をかけたいと考えています。  
メモリーデータへのset/get/updateの関数があり、updateの関数では更新した結果を戻したいと考えています。  
その場合、どのようにするのが一般的なのでしょうか。

現状は以下のようにすればどうだろうと考えています。

[code]

    func set(input: Int) {
        let semaphore = dispatch_semaphore_create(0)
        var retval:Int!
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    
            self.クラスデータ = input
    
            dispatch_semaphore_signal(semaphore)
        }
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
    }
    
    
    func get() -> Int{
        let semaphore = dispatch_semaphore_create(0)
        var retval:Int!
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    
            retval = self.クラスデータ
    
            dispatch_semaphore_signal(semaphore)
        }
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
        return retval
    }
    
[/code]

（ご指摘により、質問を修正しました）


CC BY-SA 3.0
2016-01-14T13:39:44.610
20926
2016-01-26T12:00:35.557
2016-01-26T11:29:29.770
12842
12842
question
ios swift
排他処理終了後の戻り値


最初に前提条件として、その`クラスデータ`の操作は(排他制御は必要であるが)1回あたりの処理時間はせいぜいマイクロ秒のオーダーで終了するようなデータ構造(DictionaryやArray,
Setなどはみな該当します)であるものとしておきます。

編集後にご掲載のコードは、「非同期処理の待ち合わせ」としては典型的なパターンですが、前提条件に合致するようなデータ構造を操作する場合の排他制御としては、あまり適切とは言えません。

このような排他制御の場合にsemaphoreを用いる際の基本は、

  * 排他されるべき一つの資源ごとに一つのsemaphoreを用意する
  * 使う前にwait
  * 使い終わったらsignal

と言うことです。

具体的には次のような感じになります。

[code]

    var クラスデータ_semaphore = dispatch_semaphore_create(1)
    var クラスデータ = (クラスデータの初期化)
    
[/code]

のように、排他制御したいデータ構造と対になるようにして、初期値が1になるようなsemaphoreを作成します。この`1`は、排他制御される資源を同時に使用できるスレッドが一つだけであることを表しています。それを実際に使う場合は、以下のようになります。

[code]

        func set(input: Int) {
            //使う前にsemaphoreのカウンター(使える資源数)が1以上になるのを待つ
            dispatch_semaphore_wait(クラスデータ_semaphore, DISPATCH_TIME_FOREVER)
    
            self.クラスデータ = input
    
            //使い終わったらsemaphoreのカウンターを1増やして資源の使用終了を通知する
            dispatch_semaphore_signal(クラスデータ_semaphore)
        }
    
    
        func get() -> Int {
            let retval: Int
            //使う前にsemaphoreのカウンター(使える資源数)が1以上になるのを待つ
            dispatch_semaphore_wait(クラスデータ_semaphore, DISPATCH_TIME_FOREVER)
    
            retval = self.クラスデータ
    
            //使い終わったらsemaphoreのカウンターを1増やして資源の使用終了を通知する
            dispatch_semaphore_signal(クラスデータ_semaphore)
    
            return retval
        }
    
[/code]

いかがでしょうか。わかりにくいところがあればお知らせください。


CC BY-SA 3.0
2016-01-26T12:00:35.557
21343
2016-01-26T12:00:35.557
13972
20926
answer