5

サンプルコードへのリンクは次のとおりですhttp://developer.apple.com/library/ios/#samplecode/MVCNetworking/Introduction/Intro.html

以下は、 NetworkManager.mファイルのコードスニペットです。

+ (NetworkManager *)sharedManager
// See comment in header.
{
    static NetworkManager * sNetworkManager;

    // This can be called on any thread, so we synchronise.  We only do this in 
    // the sNetworkManager case because, once sNetworkManager goes non-nil, it can 
    // never go nil again.

    if (sNetworkManager == nil) {
        @synchronized (self) {
            sNetworkManager = [[NetworkManager alloc] init];
            assert(sNetworkManager != nil);
        }
    }
    return sNetworkManager;
}

明らかに、ここにはスレッドセーフの問題があります。複数のスレッドがある場合、2つのNetworkManagerインスタンスが作成されることがあります。それでAppleは間違いを犯しましたよね?

4

3 に答える 3

2

はい、その通りです。並行性環境で問題が発生します。より良い方法は、前にダブルチェックを使用することallocです:

+ (NetworkManager *)sharedManager
{
    static NetworkManager * sNetworkManager;
    if (sNetworkManager == nil) {
        @synchronized (self) {
            if (sNetworkManager == nil) {
                sNetworkManager = [[NetworkManager alloc] init];
                assert(sNetworkManager != nil);
            }
        }
    }
    return sNetworkManager;
}

そして、Ojbective-Cを使用してシングルトンを書く方法はたくさんあります。この投稿を確認してください:私のObjective-Cシングルトンはどのように見えるべきですか?

アップデート

BobCromwellは正しい。double check lockアップルのドキュメントであるアップルでは推奨されていませんThreading Programming Guide

ダブルチェックロックは、ロックを取得する前にロック基準をテストすることにより、ロックを取得するオーバーヘッドを削減する試みです。ダブルチェックされたロックは潜在的に安全ではないため、システムはそれらを明示的にサポートしておらず、それらの使用は推奨されていません。

于 2012-04-07T06:10:13.510 に答える
1

はい、それは間違っています。sNetworkManagerasから始めてnil、2つのスレッドT1とT2を検討します。

可能性が低い場合のシナリオの1つは、次のとおりです。

T1: Determines (sNetworkManager == nil) is true
T2: Determines (sNetworkManager == nil) is true
T1: Takes the @synchronized lock
    Creates a NetworkManager 
    Sets sNetworkManager
    Releases the lock
T2: Takes the @synchronized lock
    Creates a NetworkManager 
    Sets sNetworkManager, LEAKING the first one
    Releases the lock

この質問には、より安全な方法がいくつかあります。

于 2012-04-06T06:27:33.440 に答える
0

このコードに間違いはありません。「静的」という言葉が使用されているという単純な理由から、sNetworkManagerは1つだけ作成されます。staticキーワードは、変数をグローバルとして定義するためにここで使用されますが、その関数にのみ表示されます。変数は+(NetworkManager *)sharedManagerの最初の呼び出しで割り当てられ、nullにならず、初期化されなくなります。

于 2012-04-06T06:13:33.123 に答える