1

バックグラウンド スレッド (大規模なデータベース更新のダウンロード) で多くの DB アクティビティを実行する傾向があるアプリを使用していますが、このプロセスによって UI スレッドが「枯渇」することがよくあります。@synchronized使用されるメカニズムは「公正」ではなく、バックグラウンド スレッドがすぐにロックを再取得することを可能にします。

代わりに使用できる、合理的に効率的で十分にサポートされている (そして改造するのがそれほど難しくない) (そして「公平な」) 別のメカニズムはありますか?

4

3 に答える 3

2

問題を再現できません。@synchronizedここに、および pthreads に基づいた単純なプログラム (Mac 上では実行され@synchronizedますが) があります。

void *backgroundThread(void *data)
{
    while (true)
    {
        @synchronized (globalMutex)
        {
            usleep(USEC_PER_SEC / 3);
        }
    }

    return NULL;
}

int main()
{
    pthread_t bgThread = NULL;
    globalMutex = [NSObject new];

    pthread_create(&bgThread, NULL, &backgroundThread, NULL);

    NSTimeInterval lastTime = [[NSDate date] timeIntervalSinceReferenceDate];
    while (true)
    {
        @synchronized (globalMutex)
        {
            NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceReferenceDate] - lastTime;
            NSLog(@"Main Thread 'came up for air' after %lf seconds", elapsed);

            lastTime += elapsed;
        }
    }
}

出力:

TestProj[1494:303] 0.000015 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.003136 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.000637 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.000610 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.000697 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.000576 秒後にメイン スレッドが「空中に現れた」
TestProj[1494:303] 0.000571 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.337343 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.335533 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.335253 秒後にメイン スレッドが「空中に現れた」
TestProj[1494:303] 0.335309 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.335367 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.335223 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.335754 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.335271 秒後にメイン スレッドが「空中に現れた」
TestProj[1494:303] 0.335211 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.334555 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.335245 秒後にメイン スレッドが「空中に現れた」
TestProj[1494:303] 0.335203 秒後にメイン スレッドが「空中に現れた」
TestProj[1494:303] 0.335262 秒後にメイン スレッドが「空中に現れた」
TestProj[1494:303] 0.335252 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.335667 秒後にメイン スレッドが「空中に出てきた」
TestProj[1494:303] 0.335278 秒後にメイン スレッドが「空中に現れた」
TestProj[1494:303] 0.335309 秒後にメイン スレッドが「空中に出てきた」

したがって、ロックを適切に解放していない限り、@synchronizedまさにこのシナリオで必要なものです。あなたの同期コードが実際にどのように見えるかを詳しく説明してください。

于 2013-01-15T22:37:25.283 に答える
1

私が過小評価しているように、@synchronizedは ミューテックスロックを作成する便利な方法です。それは「公正」である必要はありません。

GCDについて読むことをお勧めします。実行する必要のあるすべての作業をキューに入れるための興味深いものがたくさんあります(これにより、より良いリソース共有が提供されるはずです)。

于 2013-01-15T22:16:43.107 に答える
0

UI スレッドのブロックが心配な場合は、データベース操作用のシリアル ディスパッチ キューを作成できます。これにより、UI スレッドから DB 操作をブロックせずにキューに入れることができます (作業ブロックはヒープにコピーされ、処理されるまで保存されます)。

たとえば、UI スレッドから次のことができます。

database_queue = dispatch_queue_create("com.example.queue", NULL);

dispatch_async(database_queue, ^{
    // Operations on the DB here
});
// The UI will continue responding immediately after here...

キューは各ブロックを一度に 1 つずつ処理し、必要な同期を提供します。必要なのは、すべての DB 操作がその 1 つのキューから行われることを確認することだけです。

作業が実際に完了するまで待つ必要がある場合は、これらの特定のインスタンスで非同期呼び出しを同期呼び出しに置き換えることができます。

dispatch_sync(database_queue, ^{
    ....
    ....
于 2013-01-15T22:28:53.973 に答える