2010-10-19 5 views
3

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

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

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

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

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

ответ

2

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

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

Если вы хотите быть действительно сложным об этом, вместо передачи объекта класса вы определяете, использовать NSInvocation объект и просто invoke его на другую нить (убедитесь, что не ссылаться на один и тот же 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 ... сохраняют как приемник, так и объект до тех пор, пока они не будут выполнены, но с асинхронными вызовами может быть небольшое окно, в котором они могут исчезнуть, если вы не будете осторожны.

+0

Проблема с performSelectorOnThread: withObject: waitUntilDone: заключается в том, что при ожидании он не обрабатывает вызовы ONTO текущего потока. По крайней мере, в моих тестах это не так. то есть, если поток A выполняетSelectorOnThread: B, то B должен иметь возможность выполнятьSelectorOnThread: A как часть своей работы. –

+0

Но я буду использовать +1 для элегантного использования NSInvocation. –

+0

@ Крис Бекке: Я добавил материал, чтобы не ждать. По сути, если вы хотите не ждать и иметь возвращаемое значение, ваш второй поток должен возвращать исходный поток. Вы не можете этого избежать. – JeremyP

1

Вы изучали Distributed Objects?

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

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

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

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

+0

Хотя я хотел бы исследовать один из наиболее интересных вариантов параллелизма (например, GCD), на данный момент мне приходится иметь дело с проектом exsiting, который компенсирует отнимающий много времени синхронный код от потока пользовательского интерфейса, на рабочие потоки. Я работаю над тем, чтобы владельцы проектов принимали более крупный рефакторинг базы кода для поддержки некоторых более масштабируемых идей - на данный момент мне нужен вызов interthread «SendMessage», который запускает CFRunLoop внутренне, ожидая ответа. –

Смежные вопросы