iPhone: запуск NSThread из объекта C ++ - PullRequest
3 голосов
/ 21 января 2011

Я пишу игру для iPhone.Почти весь код написан на C ++.Теперь я хотел бы создать новый поток, используя NSThread (я хочу использовать runLoop).

Можно смешивать target-C и C ++, если код написан в файле .mm, что я и сделал.

Проблема в том, что для создания NSThread

NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(workerThreadFunction:) object:nil];
[myThread start]; 

мне нужно передать "self", которое (насколько я понимаю), "id" Objective-C - иобъект c ++ не является объектом object-c.

Итак, есть ли способ использовать NSThread в приложении на языке c ++ или я вынужден использовать pthreads?

Спасибо!

Ответы [ 4 ]

2 голосов
/ 21 января 2011

могу ли я как-то создать объект target-C, который - в своем конструкторе - принимает указатель на функцию c ++ в качестве аргумента, который он вызывает позже?

Конечно.Например:

//The C++ base
class ThreadBase
{
    virtual void Run() = 0;
};

typedef ThreadBase * (*ThreadCreator)();

//The ObjC wrapper

@interface ThreadStarter:NSObject
{
    ThreadCreator TheCreator;
}

-(void)Run;
-(id)init:(ThreadCreator)tc;
@end

@implementation ThreadStarter
-(id)init:(ThreadCreator)tc
{
    TheCreator = tc;
    return [super init];
}

-(void)Run
{
    (*TheCreator)()->Run();
}
@end

//
class MyThread: public ThreadBase
{
//...
};

ThreadBase *MyThreadCreator()
{
    return new MyThread();
}

//And finally usage

ThreadStarter *tc = [[ThreadStarter alloc]init:MyThreadCreator];
NSThread* myThread = [[NSThread alloc] initWithTarget:tc selector:@selector(Run) object:nil]; [myThread start];  

Параметризован функцией-создателем, потому что вы этого хотели.Но вы также можете параметризовать по классам.

1 голос
/ 24 января 2011

"Могу ли я как-то создать объект target-C, который в своем конструкторе принимает указатель на функцию c ++ в качестве аргумента, который он вызывает позже?"

Да, но это довольно некрасиво.

Сначала определите базовый класс обратного вызова и шаблонную версию. Это может войти в общий файл .h, который можно #includ редактировать из файлов .cpp и .mm. Также определите базовый класс CThread:

// Thread.h
#pragma once
#include <objc/objc.h> // for a cpp compatible definition of id
class Callback{
public:
  virtual void operator()(void)=0;
};

template<class T>
class ClassCallback : public Callback {
  T* _classPtr;
  typedef void(T::*fncb)(void);
  fncb _cbProc;
public:
  ClassCallback(T* classPtr,fncb cbProc):_classPtr(classPtr),_cbProc(cbProc){}
  virtual void operator()(void){
    (_classPtr->*_cbProc)();
  }
};

class CThread {
  id _thread;
public:
  void Start(Callback* cb);
};

Затем поместите реализацию CThread и его объект собеседника obj-c в файл .mm:

// Thread.mm
#import <Cocoa/Cocoa.h>
#import "Thread.h"

@interface ThreadStarter:NSObject
{
  Callback *theCallback;
}

-(void)Run;
-(id)init:(Callback*)cb;
@end

@implementation ThreadStarter
-(id)init:(Callback*)cb
{
  theCallback = cb;
  return [super init];
}

-(void)Run
{
  theCallback();
}
@end

void CThread::Start(Callback* cb){
    _thread = [[ThreadStarter alloc] init:cb];
    [NSThread detachNewThreadSelector:@selector(Run)
                       toTarget:_thread
                     withObject:nil];
  }
};

А затем в файле cpp вашего приложения вы можете:

// MyClass.cpp (doesn't even have to be .mm)
#include "Thread.h"

class MyClass {
  CThread _myThread;
  void SomeArbMethod(){
  }
public:
  MyClass(){
    _myThread.Start( new ClassCallback<MyClass>(this,&MyClass::SomeArbMethod));
  }
};
0 голосов
/ 22 января 2011

Для перефразирования моего предыдущего ответа в стиле C ++:

//The C++ base
class ThreadBase
{
    virtual void Run() = 0;
};

//The ObjC wrapper

@interface ThreadStarter:NSObject
{
    ThreadBase *TheThread;
}

-(void)Run;
-(id)init:(ThreadBase)tb;
@end

@implementation ThreadStarter
-(id)init:(ThreadBase)tb
{
    TheThread = tb;
    return [super init];
}

-(void)Run
{
    TheThread->Run();
}
@end

//
class MyThread: public ThreadBase
{
    //...         
};

//And finally usage

MyThread *Thread = new MyThread();
ThreadStarter *tc = [[ThreadStarter alloc]init:Thread];
NSThread* myThread = [[NSThread alloc] initWithTarget:tc selector:@selector(Run) object:nil];
[myThread start];  

Намного чище, ИМХО.Если вы настаиваете, что процедура запуска потока является произвольной функцией в произвольном классе, не принадлежащем вашему созданию, вот ваш ответ:

class MyThread: public ThreadBase, public MyOtherObject
{
    void Run()
    {
        DoWork(); //Function defined in MyOtherObject
    }
}

Видите ли, если вы хотите параметризовать с помощью функции-члена, у вас естьпараметризовать как по функции, так и по классу.И класс не может быть переменной времени выполнения в C ++.

0 голосов
/ 21 января 2011

Вы не можете получить классы C ++ из классов Objective C и наоборот. Разработайте объект-оболочку ObjC, который будет создавать и вызывать (но не наследовать) объект C ++. Обычно это называется «сдерживание и делегирование».

Или вы можете использовать потоки POSIX вместо NSThread.

...