美文网首页
iOS NSThread 源码分析原理,及如何实现常驻线程

iOS NSThread 源码分析原理,及如何实现常驻线程

作者: 孙掌门 | 来源:发表于2019-12-19 21:43 被阅读0次

iOS NSThread 源码分析原理,及如何实现常驻线程

- (void) start
{
  pthread_attr_t    attr;

  if (_active == YES)
    {
      [NSException raise: NSInternalInconsistencyException
                  format: @"[%@-%@] called on active thread",
        NSStringFromClass([self class]),
        NSStringFromSelector(_cmd)];
    }
  if (_cancelled == YES)
    {
      [NSException raise: NSInternalInconsistencyException
                  format: @"[%@-%@] called on cancelled thread",
        NSStringFromClass([self class]),
        NSStringFromSelector(_cmd)];
    }
  if (_finished == YES)
    {
      [NSException raise: NSInternalInconsistencyException
                  format: @"[%@-%@] called on finished thread",
        NSStringFromClass([self class]),
        NSStringFromSelector(_cmd)];
    }

  /* Make sure the notification is posted BEFORE the new thread starts.
   */
  gnustep_base_thread_callback();

  /* The thread must persist until it finishes executing.
   */
  RETAIN(self);

  /* Mark the thread as active while it's running.
   */
  _active = YES;

  errno = 0;
  pthread_attr_init(&attr);
  /* Create this thread detached, because we never use the return state from
   * threads.
   */
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  /* Set the stack size when the thread is created.  Unlike the old setrlimit
   * code, this actually works.
   */
  if (_stackSize > 0)
    {
      pthread_attr_setstacksize(&attr, _stackSize);
    }
  if (pthread_create(&pthreadID, &attr, nsthreadLauncher, self))
    {
      DESTROY(self);
      [NSException raise: NSInternalInconsistencyException
                  format: @"Unable to detach thread (last error %@)",
                  [NSError _last]];
    }
}

从上面代码可以看出,前面也是一些异常判断,然后紧接着会创建一个pthread,pthread_create,同时会设置一个启动函数nsthreadLauncher

static void *
nsthreadLauncher(void *thread)
{
  NSThread *t = (NSThread*)thread;

  setThreadForCurrentThread(t);

  /*
   * Let observers know a new thread is starting.
   */
  if (nc == nil)
    {
      nc = RETAIN([NSNotificationCenter defaultCenter]);
    }
  [nc postNotificationName: NSThreadDidStartNotification
            object: t
          userInfo: nil];

  [t _setName: [t name]];

  [t main];

  [NSThread exit];
  // Not reached
  return NULL;
}

然后我们分析这个启动函数,

会发现系统为什么发送了一个通知NSThreadDidStartNotification,然后设置名字,紧接着调用main函数,当我们的main函数调用完成之后,就会调用exit,退出,所以如果我们想实现常驻线程,只需要对main函数做手脚就可以了,那么main函数是怎么实现的呢?

- (void) main
{
  if (_active == NO)
    {
      [NSException raise: NSInternalInconsistencyException
                  format: @"[%@-%@] called on inactive thread",
        NSStringFromClass([self class]),
        NSStringFromSelector(_cmd)];
    }

  [_target performSelector: _selector withObject: _arg];
}

会发现最后利用了 [_target performSelector: _selector withObject: _arg]; 这个方法来调用我们的selector,这个就是我们传进来的selector,所以如果我们想实现常驻线程,只需要在我们穿进去的selector做手脚就可以实现了,是不是瞬间豁然开朗?

练习

- (void)viewDidLoad {
    [super viewDidLoad];

    _queue = dispatch_queue_create("com.rongcloud.sunchengxiu", DISPATCH_QUEUE_CONCURRENT);
    _dic = [NSMutableDictionary dictionary];
//    [self testGroup1];
    [self testThread];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self performSelector:@selector(print) onThread:_thread withObject:nil waitUntilDone:NO];
}
- (void)testThread{
    _thread=[[NSThread alloc] initWithTarget:self selector:@selector(print) object:nil];
    [_thread start];
}

会发现当我们touch的时候,方法没有调用,是因为在源码内部调用了exit,所以我们要实现常驻线程,经过改造

- (void)viewDidLoad {
    [super viewDidLoad];

    _queue = dispatch_queue_create("com.rongcloud.sunchengxiu", DISPATCH_QUEUE_CONCURRENT);
    _dic = [NSMutableDictionary dictionary];
//    [self testGroup1];
    [self testThread];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self performSelector:@selector(print) onThread:_thread withObject:nil waitUntilDone:NO];
}
- (void)testThread{
    _thread=[[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    [_thread start];
}
- (void)run{
    [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop]run];
}
- (void)print{
    NSLog(@"%@",[NSThread currentThread]);
}

这样就可以实现了,常驻线程.

相关文章

网友评论

      本文标题:iOS NSThread 源码分析原理,及如何实现常驻线程

      本文链接:https://www.haomeiwen.com/subject/pkbvnctx.html