Как программа Objective-C из командной строки создала свой основной поток NSThread?

Мне интересно, если сама программа target-c является объектом NSThread. Очень простой пример:

#import <Foundation/Foundation.h>
#import <stdio.h>


int main()
{
  printf("Is this a main thread? %s\n", [NSThread isMainThread] ? "yes" : "no");
  printf("This is the main thread object %p\n", [NSThread mainThread]);

  return(0);
}

Запустите его, и он дал:

Is this a main thread? yes
This is the main thread object 0x1928430

Конечно, в этой программе я не создавал свой "объект основного потока", поэтому я подозреваю, что среда выполнения target-c создала для меня объект NSThread из функции main(). Но я не знаю, как это волшебство произошло. Кто-нибудь объяснит мне, что произошло между __libc_start_main и моей функцией main()? Как класс NSThread узнает, что это основной поток?

Я скомпилировал код выше с:

clang  -Werror -g -v -I/usr/local/include -fconstant-string-class=NSConstantString -fno-objc-arc -lobjc -lgnustep-base mycode.m -o mycode

на CentOS Linux 6,5.

1 ответ

После дополнительных чтений кода я хотел бы ответить на свой вопрос для дальнейшего использования. В летнее время перед звонком [NSThread isMainThread], NSThread не был создан. Ничего особенного не произошло в и до функции main(). NSThread был создан побочным эффектом GSCurrentThread(),

Примеры кода на основе "gnustep-base-1.24.0". Из исходного файла "NSThread.m":

+ (BOOL) isMainThread
{
  return (GSCurrentThread() == defaultThread ? YES : NO);
}

Это вызывает GSCurrentThread() который возвращает текущий объект NSThread этого потока.

inline NSThread*
GSCurrentThread(void)
{
  NSThread *thr = pthread_getspecific(thread_object_key);
  if (nil == thr)
    {
      GSRegisterCurrentThread();
      thr = pthread_getspecific(thread_object_key);
      if ((nil == defaultThread) && IS_MAIN_PTHREAD)
        {
          defaultThread = [thr retain];
        }
    }
  assert(nil != thr && "No main thread");
  return thr;
}

thread_object_key является статической переменной соответствующего потока. Он был неинициализирован, поэтому объект NSThread thr будет nil и это вызывает GSRegisterCurrentThread(),

BOOL
GSRegisterCurrentThread (void)
{
  return [NSThread _createThreadForCurrentPthread];
}

Эта функция вызывает метод класса NSThread _createThreadForCurrentPthread,

+ (BOOL) _createThreadForCurrentPthread
{
  NSThread  *t = pthread_getspecific(thread_object_key);

  if (t == nil)
    {
      t = [self new];
      t->_active = YES;
      [[NSGarbageCollector defaultCollector] disableCollectorForPointer: t];
      pthread_setspecific(thread_object_key, t);
      GS_CONSUMED(t);
      return YES;
    }
  return NO;
}

Еще раз объект NSThread t будет nil и новый объект NSThead будет выделен и инициализирован кодом t = [self new], Этому объекту NSThread будет присвоен ключ pthread, который будет храниться в статической переменной thread_object_key,

Наконец мы вернулись к функции GSCurrentThread():

  if (nil == thr)
    {
      GSRegisterCurrentThread();
      // Returned from here
      thr = pthread_getspecific(thread_object_key);
      if ((nil == defaultThread) && IS_MAIN_PTHREAD)
        {
          defaultThread = [thr retain];
        }
    }

pthread_getspecific() будет вызван снова, но на этот раз переменная thread_object_key связан с объектом NSThread из _createThreadForCurrentPthread, Если defaultThread не был установлен, он будет установлен с нашим вновь созданным объектом NSThread, thr,

В конце стека [NSThread isMainThread] вернусь YES так как defaultThread имеет объект NSThread, созданный GSCurrentThread(), Отныне сам процесс может рассматриваться как объект NSThread через thread_object_key которая является статической переменной каждого процесса / потока. Вот как был создан объект NSThread для главной функции.

Другие вопросы по тегам