Отправка сообщений в ветку? - PullRequest
3 голосов
/ 19 октября 2010

Мне нужно реализовать в какао, дизайн, который опирается на несколько потоков.

Я начал с уровня CoreFoundation - я создал CFMessagePort и подключил его к CFRunLoop, но это было очень неудобно, поскольку (в отличие от других платформ) ему нужно , чтобы иметь (общесистемное) уникальное имя, и CFMessagePortSendRequest не обрабатывает обратные вызовы обратно в текущий поток во время ожидания. Можно создать мой собственный объект CFRunLoopSource, но создание моей собственной очереди, безопасной для потоков, кажется излишним.

Затем я переключился с использования потоков POSIX на NSThreads, вызвав executeSelector: onThread: для отправки сообщений другим потокам. Это намного проще в использовании, чем механизм CFMessagePort, но, опять же, executeSelector: onThread: не позволяет основному потоку отправлять сообщения обратно в текущий поток - и возвращаемого значения нет.

Все, что мне нужно, - это простой внутрипроцессный механизм (поэтому, надеюсь, мне не нужно придумывать схемы для создания «уникальных» имен), который позволяет мне отправлять сообщение (и ждать ответа) из потока A в поток B и во время ожидания сообщения разрешить потоку B отправить сообщение (и дождаться ответа) в / из потока A.

Простое: A вызывает B повторными вызовами. Ситуация, которая так обычна для одного потока, но является тупиковой ад, когда сообщения находятся между потоками.

Ответы [ 2 ]

2 голосов
/ 19 октября 2010

использовать -performSelectorOnThread: withObject: waitUntilDone: . Объект, который вы передаете, будет чем-то, что имеет свойство или другой «слот», в который вы можете поместить возвращаемое значение. Например,

SomeObject* retObject = [[SomeObject alloc] init];
[anotherObject performSelectorOnThread: whateverThread withObject: retObject waitUntilDone: YES];
id retValue = [retObject retValue];

Если вы хотите быть действительно искушенным в этом, вместо передачи объекта класса, который вы определяете, используйте NSInvocation объект и просто вызовите его в другом потоке не вызывайте одну и ту же NSInvocation одновременно для двух потоков), например,

[invocation performSelectorOnMainThread:@selector(invoke) withObject:NULL waitUntilDone:YES];

Редактировать

если вы не хотите ждать завершения обработки в другом потоке и хотите получить возвращаемое значение, вы не можете избежать обратного вызова другого потока в ваш поток. Вы по-прежнему можете использовать вызов, например

[comObject setInvocation: myInvocation];
[comObject setCallingThread: [NSThread currentThread]];
[someObject performSelectorOnMainThread: @selector(runInvocation:) withObject: comObject waitUntilDone: NO];

// in someObject's implementation

-(void) runInvocation: (ComObject*) comObject
{
    [[comObject invocation] invoke];
    [self perfomSelector: @selctor(invocationComplete:) 
                onThread: [comObject callingThread] 
              withObject: [comObject invocation]];
}

Если вам не нравится создавать новый класс для передачи потока и вызова, используйте вместо этого NSDictionary, например,

comObject = [NSDictionary dictionaryWithObjectsAndKeys: invocation, "@invocation" [NSThread currentThread], @"thread", nil];

Будьте осторожны с владением объектом. Различные методы executeSelector ... сохраняют и получатель, и объект до тех пор, пока они не будут выполнены, но при асинхронных вызовах может быть небольшое окно, в котором они могут исчезнуть, если вы не будете осторожны.

1 голос
/ 19 октября 2010

Вы изучили Распределенные объекты ?

Они обычно используются для межпроцессного взаимодействия, но нет реальной причины, по которой его нельзя ограничить одним процессом с несколькими потоками.Еще лучше, если вы пойдете по этому пути, ваш дизайн будет легко масштабироваться до нескольких процессов и даже нескольких компьютеров.

Вам также предоставляется возможность указать поведение с помощью дополнительных ключевых слов, таких как oneway, * 1008.*, out, inout, bycopy и byref. статья , написанная Дэвидом Чисналлом (из известности GNUstep), объясняет их обоснование.

Все сказанное относится к обычным предостережениям: действительно ли вам нужен многопоточный дизайн и т. Д.?Существуют альтернативы, такие как NSOperation (doc здесь ) и NSOperationQueue, которые позволяют вам явно указывать зависимости и позволять магии решать их за вас.Возможно, внимательно прочитайте Apple Руководство по программированию параллелизма , чтобы получить представление (без каламбура) о ваших возможностях.

Я предлагаю это только потому, что вы упомянули, что пытаетесь использовать традиционные потоки POSIX, и это заставляет меня поверить, что вы, возможно, пытаетесь применить знания, полученные из других ОС, и не в полной мере использовать то, что может предложить OS X.

...