在 Objective-C 中,如何标记关键区域?

lms*_*lms 5 multithreading objective-c

我有一个简单的场景,其中 aNSTimer被安排在后台线程上,每隔一段时间通过套接字发送一个数据包。然而,我的主线程负责销毁计时器和套接字。

破坏看起来像这样:

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

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

    self.connected = NO;
}
Run Code Online (Sandbox Code Playgroud)

我如何在 Objective-C 中确保一旦输入了这部分代码,在代码部分结束之前不允许调度程序挂起该线程?换句话说,我想让这个代码部分原子化。

我的理解是,该@synchronized指令是一个高层次的信号量/互斥体,以确保代码块的原子性,我需要封闭的代码块本身,以及所有的代码或者引用self.connectedself.pingTimerself.socket@synchronized指令。我的想法正确吗?

aLe*_*ion 2

据我所知,没有办法阻止操作系统抢占你的线程并在其位置上进行另一个运行。您能做的最好的事情就是同步访问。但在阅读你的代码时我推断出以下内容:

  • connect 是一个内部状态变量。
  • 您希望避免在断开连接时安排计时器。
  • 您希望避免在计划计时器时断开连接。

我认为最好尽可能避免同步。幸运的是,您正在使用 NSTimer,这将使事情变得微不足道。

NSTimer 不在后台线程上运行,而是在 NSRunLoop 上运行,并且可能在主运行循环上运行,就像您的dealloc. 计时器是运行循环的事件源。当它们触发时,它们会将一个事件排入队列,该事件在处理后又调用您的代码。由于运行循环一次处理一个事件,这意味着计划计时器中的代码和 dealloc 中的代码在另一个事件运行之前就已完全执行。这也意味着您不需要任何特殊的同步机制。

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

注意:我更喜欢直接使用状态变量,除非设置器有其他副作用。在 dealloc 中设置状态变量也是没有意义的,因为一旦方法调用完成,对象就会消失。