Еще одно редактирование:
Чтобы ответить на вопрос комментария:
какой механизм IPC используется для передачи информации между потоками? Общая память? Розетки? Обмен сообщениями с Маха?
NSThread хранит внутреннюю ссылку на основной поток, и через эту ссылку вы можете получить ссылку на NSRunloop этого потока. NSRunloop внутренне представляет собой связанный список, и при добавлении объекта NSTimer в цикл выполнения создается и добавляется в список новый элемент связанного списка. Таким образом, вы могли бы сказать, что это разделяемая память, связанный список, который на самом деле принадлежит основному потоку, просто модифицируется из другого потока. Существуют мьютексы/блокировки (возможно, даже объекты NSLock), которые гарантируют, что редактирование связанного списка будет потокобезопасным.
Псевдокод:
// Main Thread
for (;;) {
lock(runloop->runloopLock);
task = NULL;
do {
task = getNextTask(runloop);
if (!task) {
// function below unlocks the lock and
// atomically sends thread to sleep.
// If thread is woken up again, it will
// get the lock again before continuing
// running. See "man pthread_cond_wait"
// as an example function that works
// this way
wait_for_notification(runloop->newTasks, runloop->runloopLock);
}
} while (!task);
unlock(runloop->runloopLock);
processTask(task);
}
// Other thread, perform selector on main thread
// selector is char *, containing the selector
// object is void *, reference to object
timer = createTimerInPast(selector, object);
runloop = getRunloopOfMainThread();
lock(runloop->runloopLock);
addTask(runloop, timer);
wake_all_sleeping(runloop->newTasks);
unlock(runloop->runloopLock);
Конечно, это слишком упрощенно, большинство деталей здесь скрыто между функциями. Например. getNextTask вернет таймер только в том случае, если он уже должен был сработать. Если дата срабатывания для каждого таймера все еще находится в будущем и нет другого события для обработки (например, события клавиатуры, мыши из пользовательского интерфейса или отправленное уведомление), он вернет NULL.
Я все еще не уверен, в чем вопрос. селектор — это не что иное, как строка C, содержащая имя вызываемого метода. Каждый метод является обычной функцией C, и существует таблица строк, содержащая имена методов в виде строк и указателей на функции. Это самые основы того, как на самом деле работает Objective-C.
Как я написал ниже, создается объект NSTimer, который получает указатель на целевой объект и указатель на строку C, содержащую имя метода, и когда таймер срабатывает, он находит правильный метод C для вызова с помощью таблицы строк (следовательно, ему нужно строковое имя метода) целевого объекта (следовательно, ему нужна ссылка на него).
Не совсем реализация, но довольно близко к ней:
У каждого потока в Cocoa есть NSRunLoop (он всегда там, вам никогда не нужно создавать поток). PerformSelectorOnMainThread создает объект NSTimer, например этот, который срабатывает только один раз и где время срабатывания уже находится в прошлом (поэтому требуется немедленное срабатывание), затем получает NSRunLoop основного потока и добавляет туда объект таймера. Как только основной поток переходит в режим бездействия, он ищет следующее событие в своем цикле выполнения для обработки (или переходит в спящий режим, если обрабатывать нечего, и снова просыпается, как только событие добавляется). ) и выполняет его. Либо основной поток занят, когда вы планируете вызов, и в этом случае он будет обрабатывать событие таймера, как только завершит свою текущую задачу, либо в данный момент он спит, и в этом случае он будет разбужен путем добавления события и обрабатывает его немедленно.
Хорошим источником информации о том, вероятнее всего, делает это Apple (никто не может сказать наверняка, поскольку исходный код закрыт), является GNUStep. Поскольку GCC может работать с Objective-C (это не просто расширение, поставляемое только Apple, с ним может справиться даже стандартный GCC), однако наличие Obj-C без всех базовых классов, поставляемых Apple, довольно бесполезно, сообщество GNU попыталось переделать его. - реализовать наиболее распространенные классы Obj-C, которые вы используете на Mac, и их реализация — OpenSource.
Здесь вы можете загрузить последний исходный пакет.
Распакуйте его и взгляните на реализацию NSThread, NSObject и NSTimer для деталей. Я предполагаю, что Apple не сильно отличается от этого, я, вероятно, мог бы доказать это с помощью gdb, но почему они должны делать это так, как этот подход? Это умный подход, который работает очень хорошо :)
person
Mecki
schedule
29.09.2008