- When setting up your thread you must always, start and release an NSAutoRelease pool.
- The pool should be restarted every now and then to release the objects released during the runtime of the thread.
- When using Posix threads it's recommended you run an empty NSThread just to let the OS know that the app will be multithreaded.
- Setting up an OpenAL context stalls the engine by around half a second on start up, so I tend to launch it in the jobs thread to avoid stalls.
- Bumping up the priority of the render thread does improve performance slightly.
-(void)start
{
// iPhone SDK recommends launching an empty NSThread when using POSIX threads with Cocoa applications
[NSThread detachNewThreadSelector:@selector( emptyThread ) toTarget:self withObject:nil];
// Create the game thread using POSIX routines.
createThread( &PosixGameThread, self, 0, +2 );
// Create the jobs thread
createThread( &PosixJobsThread, self, 0, -2 );
}
-(void)emptyThread
{
}
Create Thread wraps the PSIOX routines required to launch a thread with a set priority.
void createThread(void *(*start_routine)(void*), void *restrict arg, int prioritySet, int priorityAdj)
{
// Create the game thread using POSIX routines.
pthread_attr_t attr;
pthread_t posixThreadID;
int returnVal;
returnVal = pthread_attr_init( &attr );
assert( !returnVal );
returnVal = pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
assert( !returnVal );
returnVal = pthread_create( &posixThreadID, &attr, start_routine, arg );
assert( !returnVal );
struct sched_param param;
int policy;
pthread_getschedparam( posixThreadID, &policy, ¶m );
assert( !returnVal );
if( prioritySet != 0 )
{
param.sched_priority = prioritySet;
}
else if( priorityAdj != 0 )
{
param.sched_priority += priorityAdj;
}
assert( param.sched_priority > 0 && param.sched_priority < 100 );
returnVal = pthread_setschedparam( posixThreadID, policy, ¶m );
assert( !returnVal );
returnVal = pthread_attr_destroy( &attr );
assert( !returnVal );
}
void* PosixGameThread(void* data)
{
// Note: autorelease pools should be created and released more frequentley if using this feature
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
uint poolRefreshCounter = 0;
EAGLView *view = (EAGLView*)data;
[view setupGameThread];
[pool release];
pool = [[NSAutoreleasePool alloc] init];
view->runningGame = YES;
while( view->runningGame )
{
if( view->paused == NO )
{
[view update];
#if DEBUGON && TARGET_IPHONE_SIMULATOR
// 20 frames a second in debug
usleep( 50000 );
#endif
}
refreshReleasePool( &pool, &poolRefreshCounter, 100 );
}
[view shutdown];
[pool release];
return NULL;
}
The jobs thread works the same way as the game thread, but owns the OpenAL context instead and starts the file I/O operations requested by the game thread.
void* PosixJobsThread(void* data)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
uint poolRefreshCounter = 0;
EAGLView *view = (EAGLView*)data;
while( view->runningGame == NO )
{
usleep( 1000000 );
}
[view->audioManager load];
usleep( 200000 );
while( view->runningGame )
{
if( [view startJobs] )
{
// 5 jobs a second
usleep( 200000 );
}
else
{
usleep( 1000000 );
}
refreshReleasePool( &pool, &poolRefreshCounter, 10 );
}
[pool release];
return NULL;
}
Refresh Release Pool handles, reseting the NSAutoreleasePool lazily for both threads.
void refreshReleasePool(NSAutoreleasePool **pool, uint *count, const uint target)
{
if( (*count)++ > target )
{
[*pool release];
*pool = [[NSAutoreleasePool alloc] init];
*count = 0;
}
}
Any questions? Feel free to ask.
No comments:
Post a Comment