2009-08-30 22 views
6

Quiero comenzar un nuevo hilo usando una función C, no un método Object-C. Probé¿Se puede utilizar una función C como selector en Cocoa?

[NSThread detachNewThreadSelector: @selector(func) toTarget: nil withObject: id(data)]; 

donde he

void func(void *data) { 
    // ... 
} 

y data es una void *, pero me da un choque en el tiempo de ejecución objc_msgSend, llamados de

-[NSThread initWithTarget:selector:object:] 

¿Qué puedo hacer yo en su lugar? ¿Es posible?

Respuesta

10

liar:

// In some .h file. #import to make the extension methods 'visible' to your code. 
@interface NSThread (FunctionExtension) 
+(void)detachNewThreadByCallingFunction:(void (*)(void *))function data:(void *)data; 
-(id)initWithFunction:(void (*)(void *))function data:(void *)data; 
@end 

// In some .m file. 
@implementation NSThread (FunctionExtension) 

+(void)startBackgroundThreadUsingFunction:(id)object 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    void (*startThreadFunction)(void *) = (void (*)(void *))[[object objectForKey:@"function"] pointerValue]; 
    void *startThreadData    = (void *)   [[object objectForKey:@"data"] pointerValue]; 

    if(startThreadFunction != NULL) { startThreadFunction(startThreadData); } 

    [pool release]; 
    pool = NULL; 
} 

+(void)detachNewThreadByCallingFunction:(void (*)(void *))function data:(void *)data 
{ 
    [[[[NSThread alloc] initWithFunction:function data:data] autorelease] start]; 
} 

-(id)initWithFunction:(void (*)(void *))function data:(void *)data 
{ 
    return([self initWithTarget:[NSThread class] selector:@selector(startBackgroundThreadUsingFunction:) object:[NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:function], @"function", [NSValue valueWithPointer:data], @"data", NULL]]); 
} 

@end 

NOTA: Escribí el código anterior y aquí por el lugar en el dominio público. (a veces a los abogados les gusta este tipo de cosas) ¡También es completamente no probado!

Siempre se puede quitar los trozos NSAutoreleasePool si se puede garantizar que la función de entrada a la rosca también crea uno ... pero es inofensivo, no tiene penalización de velocidad lo que tan nunca, y hace llamar a funciones C arbitrarias que gran parte más simple. Yo diría que solo lo mantienes allí.

Y se puede usar como tal:

void bgThreadFunction(void *data) 
{ 
    NSLog(@"bgThreadFunction STARTING!! Data: %p", data); 
} 

-(void)someMethod 
{ 
    // init and then start later... 
    NSThread *bgThread = [[[NSThread alloc] initWithFunction:bgThreadFunction data:(void *)0xdeadbeef] autorelease]; 
    // ... assume other code/stuff here. 
    [bgThread start]; 

    // Or, use the all in one convenience method. 
    [NSThread detachNewThreadByCallingFunction:bgThreadFunction data:(void *)0xcafebabe]; 
} 

Cuando se ejecuta:

2009-08-30 22:21:12.529 test[64146:1303] bgThreadFunction STARTING!! Data: 0xdeadbeef 
2009-08-30 22:21:12.529 test[64146:2903] bgThreadFunction STARTING!! Data: 0xcafebabe 
+1

+1 Las categorías de Obj-C son muy útiles a veces. – u0b34a0f6ae

+1

¡Buena idea, gracias! –

+0

No tiene sentido hacer todo esto y rodar la propia implementación, mientras que podemos haz 'dispathc_async_f()'. Probablemente sea mejor dejar la implementación de subprocesos a los ingenieros de Apple. Tal vez saben un poco mejor lo que está sucediendo en su sistema. –

3

Crea una clase Objective-C con un método que simplemente llama a esa función. Tome el selector de ese método y páselo a NSThread API.

+0

OK, sí, quiero decir, sin hacer eso. En otras palabras, quiero saber si me falta algo de sintaxis –

+1

No NSThread llama a un método, por lo que no tiene otra opción. – Mark

+5

No creo que haya una forma sintáctica simple de hacer eso. Un selector se usa para enviar un mensaje a un objeto. Enviar un mensaje no es lo mismo que simplemente llamar a una función. Los mecanismos subyacentes son un poco diferentes. –

3

Bueno, no estoy seguro si es posible, pero hay que tener en cuenta que todos los métodos de Objective-C tiene dos argumentos implícitos/ocultos, self y _cmd. Un IMP es generalmente typedef 'D como esta:

typedef id (*IMP)(id,SEL,...); 

Si desea métodos Jerry-plataforma y selectores, es necesario tener un método que se parece a lo siguiente:

void func (id self, SEL _cmd, void *firstParameter); 

Pero incluso después de eso , debe registrar un nombre de selector con el tiempo de ejecución, luego debe asociar ese selector con el método, pero esto se hace clase por clase (es decir, las clases pueden tener diferentes implementaciones del mismo nombre de selector), por lo que al menos necesitas tener una clase ficticia.

Es mucho, mucho más simple sólo para crear una clase ficticia y la instancia de relleno de esa clase de llamar a la API de tiempo de ejecución diferentes, para simplemente NSThread para invocar una única función C.

0

Quiero empezar un nuevo hilo usando una función de C, no es un método objetivo-C

Entonces, ¿por qué no sólo tiene que utilizar:

  1. hilos POSIX,
  2. GCD?

dispatch_async_f()(man) es adecuado exactamente para este propósito.

Cuestiones relacionadas