1

私がしていることの1つは次のとおりです。

-(void)GrabbingProcess:(void (^)())block;
{
    self.OtherGrabbingIndicator +=1;
    block();
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
        self.OtherGrabbingIndicator -=1;
    });
}

バックグラウンドで時間がかかる可能性のあるものを実行したいときはいつでも、次のようなことをします

[Grabclass grab] GrabbingProcess:^{//データを取得するなどの操作を行います。}];

そのような関数とそのようなデータはたくさんあります。たとえば、最初はすべての企業IDを取得します。次に、別のスレッドでビジネスのすべての詳細を取得します。

これらのスレッドがすべて終了した時刻を知り、適切な通知を投稿したいと思います。

私の解決策の問題は、しばらくすると、self.OtherGrabbingIndicatorの値が2または3前後でホバリングし、それらのスレッドがすべて終了したとしても、決して下がらないことです。

どういうわけか自己の一部。OtherGrabbingIndicator+=1; 「リーク」され、self.OtherGrabbingIndicator-=1と一致しません。どうしてそのリークが起こるのだろうか?

4

1 に答える 1

1

ブロックを非同期で実行し、ブロックがいつ実行されるかを確認する場合、適切なツールはですdispatch_group。を使用して特定のグループとキューにブロックをディスパッチできますdispatch_group_async()。グループは、ブロックが終了したときに追跡します。次に、グループで同期的に終了するのを待つか、グループがで終了しdispatch_group_wait()たときに呼び出されるブロックを登録することができますdispatch_group_notify()


上記のソリューションが機能しない理由は、スレッドセーフな方法でカウンターにアクセス/変更していないためです。問題を引き起こす一連の些細なイベントを次に示します。

開始:self.OtherGrabbingIndicatorは1
スレッドA:自己を読み取ります。OtherGrabbingIndicator
スレッドB:自己を読み取ります。OtherGrabbingIndicator
スレッドA:読み取り値をインクリメントしてselfに書き戻します。OtherGrabbingIndicator
スレッドB:読み取り値をインクリメントしてself.OtherGrabbingIndicatorに書き戻します。
終了:self.OtherGrabbingIndicatorは2です

2つのスレッドがそれをインクリメントしようとしても、1つだけが「成功」し、もう1つのインクリメントを失うことになります。これは、デクリメント中にも発生する可能性があります。ディスパッチグループを使用すると、この問題は解消されます。


ちなみに、は絶対に使用しないでくださいdispatch_get_current_queue()。これは、実際のコードで使用されることは想定されていないデバッグ関数です。主な理由は、1つのキューで実行しているだけでなく、キューの階層全体で同時に実行しているためですが、この関数は1つのキューについてしか通知できません。さらに、誰かのプライベートキューで実行している可能性があり、自分でそのキューにディスパッチするべきではありません。

于 2012-06-05T08:07:44.793 に答える