5

NSTimerバックグラウンド スレッドでソケットを介してパケットを頻繁に送信するようにスケジュールされている単純なシナリオがあります。ただし、私のメインスレッドは、タイマーとソケットを破棄する責任があります。

破壊は次のようになります。

if (self.connected) {
    [self.pingTimer invalidate];

    if (self.socket != -1) {
        close(self.socket);
        self.socket = -1;
    }

    self.connected = NO;
}

Objective-C で、コードのこのセクションが入力されると、コード セクションが終了するまでスケジューラがこのスレッドを中断できないようにするにはどうすればよいですか? つまり、このコード セクションをアトミックにしたいのです。

私の理解では、@synchronizedディレクティブは高レベルのセマフォ/ミューテックスであるため、そのコード ブロックのアトミック性を確保するには、コード ブロック自体とself.connectedself.pingTimerおよびディレクティブself.socketを参照するすべてのコードを囲む必要があります。@synchronized私はこれを考えるのが正しいですか?

4

2 に答える 2

3

@synchronized一方向です。もう 1 つは、NSLockまたはを使用することNSRecursiveLockです。プレーンな POSIX pthread ロック プリミティブを使用することもできます。マルチスレッド ガイドを参照してください。

@interface Stuff 
{
    NSLock* lock;
    int cell;
}

- (int) cellValue;
- (void) someOperation;

@end

@implementation Stuff

- (id) init  
{
    if (self = [super init]) 
    {
        lock = [[NSLock alloc] init];
        cell = 0;
    }
    return self;
}

- (int) cellValue 
{
    [lock lock];
    @try
    {
        return cell;
    }
    @finally 
    {
        [lock unlock];
    }
}

- (void) someOperation 
{
    [lock lock];
    @try
    {
        // Do something involving access to stuff protected by
        // the lock (only cell here, but could be more, of course)
    }
    @finally 
    {
        [lock unlock];
    }
}

@end

を使用する@synchronizedと、上記のコードはより単純になります。

- (int) cellValue 
{
    @synchronized (self)
    {
        return cell;
    }
}
于 2012-09-21T08:46:10.440 に答える
2

私の知る限り、OS がスレッドをプリエンプトし、代わりに別のスレッドを実行するのを防ぐ方法はありません。最善の方法は、アクセスを同期することです。しかし、あなたのコードを読むと、次のように推測されます。

  • connected は内部状態変数です。
  • 切断中にタイマーがスケジュールされるのを避けたい。
  • タイマーがスケジュールされている間は、切断を避けたいと考えています。

可能な限り同期を避けるのが最善だと思います。幸いなことに、あなたは NSTimer を使用しているので、物事は簡単です。

NSTimer はバックグラウンド スレッドでは実行されませんが、NSRunLoop で実行され、おそらくメインの実行ループで実行されますdealloc。タイマーは、実行ループのイベント ソースです。それらが発生すると、イベントがキューに入れられ、処理されたときにコードが呼び出されます。実行ループは一度に 1 つのイベントを処理するため、スケジュールされたタイマーのコードと dealloc のコードが、もう一方が実行される前に完全に実行されることを意味します。また、特別な同期メカニズムが必要ないことも意味します。

- (void) dealloc
{
   // ...
   if (_connected) {
       [_pingTimer invalidate];
       if (_socket != -1)
           close(_socket);
   }
   // ...
   [super dealloc];
}

注: セッターに他の副作用がない限り、できる限り状態変数を直接使用することを好みます。また、メソッド呼び出しが完了するとオブジェクトが消えるため、dealloc で状態変数を設定しても意味がありません。

于 2012-09-22T11:41:14.237 に答える