1

自動解放されたオブジェクトがあり、それを別のスレッドに提供する必要がある場合、最善の方法は何ですか?

スレッド 0 で自動解放されるオブジェクトがあるとします。このオブジェクトについてスレッド 1 に伝え、スレッド 1 はそれを必要とするため保持します。その後、完了し、リリースします。問題ない。スレッド 0 が再び実行され、その自動解放プールが空になると、保持カウントが 1 であることがわかり、自動解放されたオブジェクトであるため、割り当てが解除されます。すべて問題ないので、スレッドは関係ありません。右?

ちなみに、これはもともとインタビューの質問でした。インタビュアーは、自動解放されたオブジェクトを別のスレッドに渡すことはできないと主張しました。彼はそれについてほとんど怒っているようだった。技術面接で、自分は何でも知っていると信じている人にますます遭遇します。

4

3 に答える 3

0

自動解放されたオブジェクトを他のスレッドに直接渡すべきではありません。

このコードで

id _sharedVariable; // ivar
NSConditionLock *_lock;

- (void)thread1
{
    id objectNeedToPass = [[NSObject new] autorelease];
    [_lock lock];
    _sharedVariable = objectNeedToPass;
    [_lock unlockWithCondition:1];
}

- (void)thread2
{
    while (true)
    {
        [_lock lockWithCondition:1];
        id objectReceived = [_sharedVariable retain];
        [_lock unlockWithCondition:0]
        process(objectReceived );
        [objectReceived release];
    }
}

thread2 は_sharedVariable、解放されたオブジェクトを保持している (そしてクラッシュする)可能性があります

これを行う可能性があるため

thread 1 create and autorelease object
thread 1 assign it to the shared variable
thread 1 release the object
object deallocated
thread 2 read the object
thread 2 retain the object - crash

問題を解決するには、保持されたオブジェクトを渡す必要があります

id _sharedVariable; // ivar
NSConditionLock *_lock;

- (void)thread1
{
    id objectNeedToPass = [[NSObject new] autorelease];
    [_lock lock];
    _sharedVariable = [objectNeedToPass retain];
    [_lock unlockWithCondition:1];
}

- (void)thread2
{
    while (true)
    {
        [_lock lockWithCondition:1];
        id objectReceived = _sharedVariable;
        [_lock unlockWithCondition:0]
        process(objectReceived );
        [objectReceived release];
    }
}

ただし、2 番目のスレッドがオブジェクトの解放に失敗し、コードの保守が困難になると、メモリ リークが発生する可能性があります (保持/解放のバランスが取りにくい)。

于 2013-11-06T02:41:18.307 に答える
0

通常の Cocoa メモリ管理ルールに従っている限り、何も心配する必要はありません。ルールに従っている限り、「別のスレッドに提供する」方法はすべて正常に機能します。

「別のスレッドに何かを提供する」ときはいつでも、非同期です(ロックを使用して同期クロススレッド実行などを行っている場合を除く)。つまり、このスレッドの現在の関数が範囲外になった後、他のスレッドがそれを使用する可能性があります (おそらく使用する可能性があります)。現在の実行より長く存続する必要があるオブジェクトを保存するときはいつでも、それを保持する必要があります。インスタンス変数またはグローバル変数に直接格納する場合は、メモリ管理規則に従って、それを保持する責任があります。ある種のコンテナオブジェクトに保存している場合、そのオブジェクトはそれを保持する責任があります。そのため、ルールに従っていれば、心配する必要はほとんどありません。

を使用して、人々が別のスレッドで物事を実行する一般的な方法を考えてみましょう-performSelector:onThread:withObject:waitUntilDone:。が false の場合waitUntilDone、この関数はレシーバー、セレクター、および引数をある種のオブジェクトに格納し、他のスレッドが実行する準備が整うまで待機します。したがって、この関数は、レシーバーとオブジェクトをこの構造に配置するときに保持し、構造が破棄されるときに解放する必要があります。確かにそうです-メソッドのARC以前のドキュメントを読むと、 「このメソッドは、セレクターが実行されるまでレシーバーとargパラメーターを保持します」と書かれています。

したがって、基本的にはメモリ管理規則で十分です。オブジェクトをインスタンス変数に格納する場合は、それを保持する必要があります。それを他の関数に渡す場合、それを処理するのは彼らの仕事です。

于 2013-11-07T11:29:42.743 に答える