20

中断されたタイマーをキャンセルしてから解放しようとしていますが、「dispatch_release」を呼び出すと、すぐに EXC_BAD_INSTRUCTION が発生します。

これは、タイマーで実行する有効な一連のアクションではありませんか?

タイマーの作成と一時停止:

@interface SomeClass: NSObject { }
@property (nonatomic, assign) dispatch_source_t             timer;
@end

// Class implementation
@implementation SomeClass

@synthesize timer = _timer;

- (void)startTimer 
{
    dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 
                                    0, 0, globalQ); 

    dispatch_time_t startWhen = dispatch_walltime(DISPATCH_TIME_NOW, NSEC_PER_SEC * 1);
    dispatch_source_set_timer(_timer, startWhen, 1 * NSEC_PER_SEC, 5000ull);

    dispatch_source_set_event_handler(_timer, ^{
        // Perform a task 

        // If a particular amount of time has elapsed, kill this timer
        if (timeConstraintReached)
        {
            // Can I suspend this timer within it's own event handler block?
            dispatch_suspend(_timer);
        }
    });

    dispatch_resume(_timer);
}

- (void)resetTimer
{
    dispatch_suspend(_timer);

    dispatch_source_cancel(_timer);

    // dispatch_release causes 
    // 'EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    dispatch_release(_timer);

    self.timer = nil;    
}
@end

さらに、タイマー ソースの event_handler ブロック内で dispatch_suspend を呼び出すことはできますか?

どんな助けでも大歓迎です。

4

1 に答える 1

31

クラッシュする理由は、次のコードが原因です。

void
_dispatch_source_xref_release(dispatch_source_t ds)
{
    if (slowpath(DISPATCH_OBJECT_SUSPENDED(ds))) {
        // Arguments for and against this assert are within 6705399
        DISPATCH_CLIENT_CRASH("Release of a suspended object");
    }
    _dispatch_wakeup(ds);
    _dispatch_release(ds);
}

dispatch_source_tそのため、中断された をリリースすることはできません。おそらく、一時停止したくないだけだresetTimerと思います。

なぜ彼らがこのように書いたのかについてドキュメントには何も見つかりませんが(コメントは、私たちが決して見ることのないレーダーにある長所と短所をほのめかしています)、私にできることは、ドキュメントを参照することだけです言います

dispatch_suspend および dispatch_resume メソッドを使用して、ディスパッチ ソース イベントの配信を一時的に中断および再開できます。これらのメソッドは、ディスパッチ オブジェクトのサスペンド カウントを増減します。その結果、イベント配信を再開する前に、dispatch_suspend への各呼び出しと一致する dispatch_resume への呼び出しのバランスを取る必要があります。

中断されたディスパッチソースを解放できないとは言いませんが、各呼び出しのバランスをとる必要があると言っているので、内部でディスパッチセマフォを使用しているという線に沿ったものであると想定していますリリースする前にバランスを取る必要があります。それは私の推測ですが:-)。

「タイマーソースのevent_handlerブロック内でdispatch_suspendを呼び出すことはできますか」について。はい、次のドキュメントに従って、できると確信していますdispatch_suspend

一時停止は、呼び出し時に実行されているブロックの完了後に発生します。

于 2012-03-05T19:00:44.450 に答える