iPhone:从 C++ 启动 NSThread目的

发布于 2024-10-13 11:26:25 字数 469 浏览 5 评论 0原文

我正在为 iPhone 编写一款游戏。几乎所有代码都是用 C++ 编写的。现在我想使用 NSThread 创建一个新线程(我想使用 runLoop)。

如果代码写在 .mm 文件中,就可以混合 Objective-C 和 C++,我就是这么做的。

问题是,为了创建 NSThread,

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

我需要传递“self”(据我所知),这是一个 Objective-C“id”,而 C++ 对象不是 Objective-C 对象。

那么 - 有没有办法在 C++ 应用程序中使用 NSThread 还是我被迫使用 pthreads?

谢谢!

I'm writing a game for the iPhone. Almost all the code is written in C++. Now I'd like to create a new thread using NSThread (I want to use the runLoop).

It's possible to mix objective-C and C++ if the code is written in a .mm file, which I did.

The problem is, that for creating a NSThread

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

I need to pass "self" which (as far as I understand it) an Objective-C "id" - and a c++ object is not an objective-c object.

So - is there a way to use NSThread in a c++ aplication or am I forced to use pthreads?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

惜醉颜 2024-10-20 11:26:25

<块引用>

我能否以某种方式创建一个 Objective-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];  

它由创建者函数参数化,因为你想要它如此。但您也可以按类别进行参数化。

can I somehow create an objective-C object which - in it's constructor - takes a c++ function pointer as an argument which it calls later?

Sure. Like this:

//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];  

It's parametrized by a creator function because you wanted it so. But you can parametrize by class as well.

路还长,别太狂 2024-10-20 11:26:25

“我能以某种方式创建一个 Objective-C 对象吗?在它的构造函数中,它接受一个 C++ 函数指针作为稍后调用的参数?”

是的,但是它相当丑陋。

首先,定义回调基类和模板化版本。这可以进入一个通用的 .h 文件,该文件可以从 .cpp 和 .mm 文件中#include编辑。还定义一个基本的 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 buddy 对象放入 .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));
  }
};

"can I somehow create an objective-C object which - in it's constructor - takes a c++ function pointer as an argument which it calls later?"

Yes, but its rather ugly.

First, define a callback baseclass, and a templated version. This can go into a generic .h file that can be #included from .cpp and .mm files. Also define a basic CThread class:

// 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);
};

Next, put the implementation of CThread, and its obj-c buddy object, in a .mm file:

// 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];
  }
};

And then, in your application's cpp file, you can:

// 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));
  }
};
我要还你自由 2024-10-20 11:26:25

您不能从 Objective C 类派生 C++ 类,反之亦然。设计一个包装器 ObjC 对象,该对象将实例化并调用(但不继承)C++ 对象。这通常被称为“遏制和授权”。

或者您可以使用 POSIX 线程而不是 NSThread。

You cannot derive C++ classes from Objective C classes and vice versa. Design a wrapper ObjC object that would instantiate and call (but not inherit from) the C++ one. This is generally called "containment and delegation".

Or you can use POSIX threads instead of NSThread.

铁轨上的流浪者 2024-10-20 11:26:25

对于我之前的答案的 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++ 中的运行时变量。

For a C++-style rephrasing of my previous answer:

//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];  

Much cleaner this way, IMHO. If you're insist that the thread start routine is an arbitrary function in an atrbitrary class not of your creation, here's your answer:

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

You see, if you want to parametrize by member function, you have to parametrize by both function and class. And class cannot be a run-time variable in C++.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文