Как программа 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 для главной функции.