autoreleased with no pool in place

rjvbertin
Unregistered
 
Post: #1
I'm hoping here someone can help me out with this one.

I've made my first attempt at threading, closely following the example in an example file (particles.c) from GLFW. As in that particle simulator, I have a main thread that does the imaging and event handling, and another thread that does, well, moving particle simulation. My application shows a whole series of such simulations, doing other things in between. The easiest way I found to handle that is to let the particle thread die when finished, and launch a new one when starting a new animation.

Every time I launch a new thread (even the 1st time), I get a whole row of messages

Quote:2004-11-16 19:43:45.479 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x149e770 of class NSCFNumber autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.480 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x14ac530 of class NSCFDictionary autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.481 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x14ac6b0 of class NSCFNumber autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.482 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x14ac6c0 of class NSCFDictionary autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.482 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x14ac590 of class NSCFArray autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.483 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x149e850 of class NSCFArray autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.483 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x14ac5b0 of class NSCFArray autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.484 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x14ac580 of class NSCFArray autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.484 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x149fd70 of class NSCFString autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.485 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x14a4d00 of class NSCFString autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.485 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x149fd70 of class NSCFString autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.486 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x14a4d00 of class NSCFString autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.486 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x14a4d00 of class NSCFString autoreleased with no pool in place - just leaking
2004-11-16 19:43:45.488 MatchSpeed-simulate-SDL[27096] *** _NSAutoreleaseNoPool(): Object 0x14938c0 of class NSCFString autoreleased with no pool in place - just leaking

which I do not get when I do not use multithreading. Google shows that a lot of others wonder about these errors, but gave me no answer as to how to avoid them. Can anyone here help me? Thanks!
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #2
Each thread that uses Obj-C objects (appkit, foundation etc, directly or indirectly) must have an autorelease pool in place. This is explained in the documentation for NSAutoReleasePool.

Just wrap your thread with
Code:
NSAutoreleasePool     *autoreleasepool = [[NSAutoreleasePool alloc] init];
    // do thread work
    [autoreleasepool release];

NSApplication does this for you automatically in the main thread.
Quote this message in a reply
rjvbertin
Unregistered
 
Post: #3
arekkusu Wrote:Just wrap your thread with
<ObjC code>
NSApplication does this for you automatically in the main thread.

Thanks, but then how is it possible that none of the examples coming with SDL, nor those coming with GLFW do this wrapping, and yet don't give this sort of warning messages?

Also, can code with this effect be written in plain C?
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #4
NSAutoReleasePool only affects Objective C objects. SDL and other cross-platform frameworks generally don't know anything about Obj-C.
Quote this message in a reply
rjvbertin
Unregistered
 
Post: #5
arekkusu Wrote:NSAutoReleasePool only affects Objective C objects. SDL and other cross-platform frameworks generally don't know anything about Obj-C.

Well... gues how SDL's OS X specific functions are implemented? The file extension is .m, to give you a small hint :)

More seriously: so as long as you don't use any Obj-C, you won't see these warnings? That would explain why they don't occur with glfw (which is just plain C). But it does not explain why they also don't occur with SDL's threading examples.

A thread in SDL is created with SDL_CreateThread( tfun, data ), and that new thread dies when tfun returns. Presuming that tfun is called from an Objective C file, would it be enough to wrap its invocation?
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #6
Quote:Each thread that uses Obj-C objects (appkit, foundation etc, directly or indirectly)

If no Obj-C objects are allocated, you won't get a warning. But objects could be allocated indirectly; I don't know what SDL does, or what your thread does. If SDL's platform specific hooks are implemented in Obj-C, I'd expect that the autorelease pool would already be set up for you, but...

Anyway, you can set up a pool as shown. You have to wrap the thread implementation though, not the invocation. The pool has to be created in the thread before any objects are alloc'd.
Quote this message in a reply
rjvbertin
Unregistered
 
Post: #7
I think I've figured out what happens.

SDL's OS X specific routines are implemented in Obj.C. Its threading implementation, however, is *not*. This explains why you can do multithreading, and not get any warnings as long as your non-main thread(s) do(es)n't call any Obj.C code. Whether or not that means you also should not do IO, for instance, without wrapping remains to be seen and is not relevant now.

I got the warnings because it turned out that I changed my window title from within the new thread, with SDL_WM_SetTitle. This was easy enough to trace with a gdb breakpoint on _NSAutoReleaseNoPool.

The solution to the wrapping is quite simple, given SDL's pure POSIX/C implementation of threading. I wrote a minimal little function in a minimal little Obj.C. file:

Code:
#if defined(__MACH__) || defined(__APPLE_CC__)

/* See comment in graftool-SDL.h */

#define NO_ENUM_BOOLEAN

#import <Cocoa/Cocoa.h>

#include "SDL/graftool-SDL.h"

IDENTIFY( "Graphics Routines; SDL extension stub routine to wrap a thread-function with proper autoreleasing code (Obj.C/Quartz)");

int SDL_ThreadFunction( void *data )
{ SDL_ThreadFunctionData *threaddata= (SDL_ThreadFunctionData*) data;
  int r= 0;
    if( threaddata && threaddata->function ){
      NSAutoreleasePool *autoreleasepool= [[NSAutoreleasePool alloc] init];
        threaddata->return_value= r= (*threaddata->function)( threaddata->data );
        [autoreleasepool release];
    }
    return(r);
}

#endif

with in the header file:

Code:
/* 20041117: when using threads with SDL on Mac OS X, one needs to make sure that each thread's code is properly wrapped
\ with some Objective C code dealing with autorelease. If that is not done, one will get a whole avalanch of
\ 'autoreleased with no pool in place -- just leaking' log messages each time an Objective C (read: system call)
\ routine is called.
\ The solution is, instead of calling
\     SDL_CreateThread( theFunction, itsData );
\ to do:
\    SDL_ThreadFunctionData theFunctionWrap= { theFunction, itsData };
\    SDL_CreateThread( SDL_ThreadFunction, &theFunctionWrap );
\ SDL_ThreadFunction will install the proper autorelease object, *then* call your function. SDL threads die
\ when your function exits, so that provides a clean hook to cleanup the autorelease code.
\
\ This is just a stub on other platforms (X11).
*/
typedef struct SDL_ThreadFunctionData{
    int (*function)( void *data );
    void *data;
    int return_value;
} SDL_ThreadFunctionData;

extern int SDL_ThreadFunction( void *data );

I link with that module, and then do as described in the comment.

It works. Thanks again. And I'm now thinking of an elegant way to defer the SDL call(s) that caused the warning in the first place to the main thread ;^)
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #8
I doubt it's safe to call SDL_WM_SetTitle (or any other function that interacts with the GUI) from a non-main thread. Virtually nothing in SDL or Cocoa is threadsafe in any way.

Sure, it may work for you on your hardware on this OS release, but it's highly likely to break elsewhere or, er, elsewhen.
Quote this message in a reply
rjvbertin
Unregistered
 
Post: #9
I know. That's why I'm now looking into ways of deferring events leading to this kind of thing to the main thread. I also do get an error, BTW, about trying to lock a mutex that isn't owned by the thread ("SDL error mutex not owned by this thread "). I'm a bit amazed that mutexes can be owned by a thread (the idea being that different threads can mutually exclude others with them), but, well, why not :)
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  How do I place all of my UI elements to be subviews of another view/window? xenocide 2 2,751 Feb 1, 2009 08:32 PM
Last Post: xenocide
  Good place to start 3D programming CarbonX 3 3,181 Jul 19, 2003 11:00 PM
Last Post: CarbonX