0

メインスレッドを含むsqlite3データベースに複数のスレッドが書き込むことができるマルチスレッドアプリケーションを構築しています。ミューテックスに使用する静的パブリック変数を宣言しました。

@implementation Application

#pragma mark -
#pragma mark Static Initializer
static NSString * SubmitChangesLock = nil;

+ (void)initialize {
    [super initialize];
    SubmitChangesLock = [[NSString alloc] initWithString:@"Submit-Changes-Lock"];
}

+ (NSString *)submitChangesLock {
    return SubmitChangesLock;
}

@end

データベースに書き込む必要がある各メソッド内では、その変数を @synchronized ディレクティブと共に使用して、データベースに書き込むセクションをロックしています。

- (void)method1FromClass1 {
    @synchronized ([Application submitChangesLock]) {
        // write to the database here...
    }
}

- (void)method2FromClass2 {
    @synchronized ([Application submitChangesLock]) {
        // write to the database here...
    }
}

すべてが正常に機能しましたが、これらのメソッドのいずれかがメインスレッドから呼び出されると、ミューテックスが再びロック解除されるのを待ってフリーズすることがありますが、そうではありませんでした。問題は、これがメインスレッドとコードからのいくつかの呼び出しでのみ発生することですデータベースへの書き込みは間違いなく有限であるため、メインスレッドがミューテックスのロックが解除されるのを待ち続ける理由と、そもそもロックが解除されない理由を特定できませんでした。

注: このミューテックスによって他のスレッドはブロックされず、メインのみがブロックされました。

編集: performSelectorOnMainThread:waitUntilDone を使用して @synchronized ディレクティブを置き換えようとしました:

- (void)writeToDatabase {
    // write to the database here...
}
- (void)method2FromClass2 {
    [self performSelectorOnMainThread:@selector(writeToDatabase) withObject:nil waitUntilDone:YES];
}

正常に動作していますが、ユーザーの操作をブロックしないように、メイン スレッドに多くの負荷がかからないようにしています。

どんな助けでも大歓迎です、そして前もって感謝します。

4

1 に答える 1

2

iOSには、単純な状況から中程度に複雑な状況でのスレッド/ロックの処理を回避するのに役立つ機能があります。

deanWombourneが提案するように、 NSOperationQueueandを1に設定すると、すべての作業をバックグラウンドスレッドにオフロードできます。キュー内の既存のクラスのコードを簡単に再利用できるsetMaxConcurrentOperationCount:便利なクラス()もあります。NSInvocationOperation

バックグラウンドで実行されているこれらのメソッドがUIに表示される内容に影響を与える場合は、いつperformSelectorOnMainThread:withObject:waitUntilDone:でも必要なものを更新するために使用できます。

このようにすると、メインスレッドをDBアクティビティでブロックすることはありません。メインスレッドをブロックするとUIがフリーズするので、これは間違いなく物事を行う方法です。

于 2012-01-04T12:31:07.733 に答える