Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > Multithreading problem

Multithreading problem
Thread Tools
Fresh-Faced Recruit
Join Date: Dec 2001
Location: Wisconsin
Status: Offline
Reply With Quote
Jul 2, 2002, 06:11 PM
 
This is my first time using threads so I am probably doing this all wrong but anyway...

_NSAutoreleaseNoPool(): Object 0xc6220 of class NSCFString autoreleased with no pool in place - just leaking

I am writing a simple checkers program and I want the computer to think in the background so I call
[NSThread detachNewThreadSelector:@selector(chooseMoveFromGa me toTarget:opponent withObject:game];

ChooseMoveFromGame in turn calls another function which call other functions and so on. First, I had my GameController class be an observer of NSThreadWillExitNotification so I could update the game with the move choosen. This resulted in some autoreleased arrays leaking everytime the computer moves. Insead of using the notification, I have chooseMoveFromGame calls the object that called it to send back the move it has decided upon. This works fine and I never have any memory leaks until the game is over and the computer wins making the final move. Then I get that error above four times. Can anyone explain this to me or suggest a better way to do this? I think my problem has to do with finding the move once the thread is complete.

GameController Class:
- (void)updateCheckersMove *)move
{
NSLog(@"GameController: Update Method Called");
[move retain];
[game update:move];
[move release];
[checkersView updateWithGame:game];
if ([game winner] != -1)
[self restart]; // Problem here when it was the computer's move
else if ((opponent != nil) && ([game turn] == [opponent color])) {
[checkersView allowMove:NO];
[NSThread detachNewThreadSelector:@selector(chooseMoveFromGa me toTarget:opponent withObject:game];
} else
[checkersView allowMove:YES];
}

Opponent Class:
- (void)chooseMoveFromGameCheckersGame *)game
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSArray * moves = [game allMovesForColor:myColor];
[moves retain];
if (finalMove != nil) {
[finalMove release];
finalMove = nil;
}
if ((moves != nil) && ([moves count] > 0)) {
switch(type) {
case chimp:
[self chimpAI:game];
break;
case child:
[self childAI:game];
break;
case teenager:
[self teenagerAI:game];
break;
default:
[self adultAI:game];
break;
}
}
[moves release];
[delegate update:finalMove]; // Alternative to the notification
[pool release];
[NSThread exit];
}
     
seppak  (op)
Fresh-Faced Recruit
Join Date: Dec 2001
Location: Wisconsin
Status: Offline
Reply With Quote
Jul 4, 2002, 11:51 PM
 
I have found if I don't release the pool nothing leaks. Apparently the pool is released when the thread exits. I use the notification to tell the main thread the move was found. This works, however, I usually randomly get a Sigbus error. I have no idea why. This is what it looks like in the debugger: <a href="http://homepage.mac.com/seppak/error.png" target="_blank">http://homepage.mac.com/seppak/error.png</a> . If anyone could help fix this that would be great. Here is the source: <a href="http://homepage.mac.com/seppak/CheckersSource.dmg" target="_blank">http://homepage.mac.com/seppak/CheckersSource.dmg</a> . Right now it is pretty ugly in some spots(the checkers Pieces) and the computer doesn't play very well but that isn't the problem....
Oh yeah, if you find out how to fix it, don't send me the source, just tell me how to fix it...I'd prefer to understand why this is happening.

<small>[ 07-05-2002, 12:59 AM: Message edited by: seppak ]</small>
     
Junior Member
Join Date: Mar 2001
Status: Offline
Reply With Quote
Jul 8, 2002, 04:31 PM
 
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif">Originally posted by seppak:
<strong>This is my first time using threads so I am probably doing this all wrong but anyway...

_NSAutoreleaseNoPool(): Object 0xc6220 of class NSCFString autoreleased with no pool in place - just leaking

I am writing a simple checkers program and I want the computer to think in the background so I call
[NSThread detachNewThreadSelector:@selector(chooseMoveFromGa me toTarget:opponent withObject:game];

ChooseMoveFromGame in turn calls another function which call other functions and so on. First, I had my GameController class be an observer of NSThreadWillExitNotification so I could update the game with the move choosen. This resulted in some autoreleased arrays leaking everytime the computer moves. Insead of using the notification, I have chooseMoveFromGame calls the object that called it to send back the move it has decided upon. This works fine and I never have any memory leaks until the game is over and the computer wins making the final move. Then I get that error above four times. Can anyone explain this to me or suggest a better way to do this? I think my problem has to do with finding the move once the thread is complete.

GameController Class:
- (void)updateCheckersMove *)move
{
NSLog(@"GameController: Update Method Called");
[move retain];
[game update:move];
[move release];
</font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">The retain and release above are spurious; you can safely remove them
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif">
[checkersView updateWithGame:game];
if ([game winner] != -1)
[self restart]; // Problem here when it was the computer's move
else if ((opponent != nil) && ([game turn] == [opponent color])) {
[checkersView allowMove:NO];
[NSThread detachNewThreadSelector:@selector(chooseMoveFromGa me toTarget:opponent withObject:game];
} else
[checkersView allowMove:YES];
}

Opponent Class:
- (void)chooseMoveFromGameCheckersGame *)game
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSArray * moves = [game allMovesForColor:myColor];
[moves retain];
</font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">The retain here (and the release below) are spurious as well. The object will not be deallocated until the pool is released.
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif">
if (finalMove != nil) {
[finalMove release];
finalMove = nil;
}
</font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">The if statement above is not necessary. Replace it with:
[finalMove release];
finalMove=nil;

Remember that a message sent to nil is ignored and returns nil.
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif">
if ((moves != nil) && ([moves count] &gt; 0)) {
</font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">Using that property above, this can simply be written if ([moves count] &gt; 0) {

</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif">
switch(type) {
case chimp:
[self chimpAI:game];
break;
case child:
[self childAI:game];
break;
case teenager:
[self teenagerAI:game];
break;
default:
[self adultAI:game];
break;
}
}
[moves release];
</font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">You can remove the [moves release] above
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif">
[delegate update:finalMove]; // Alternative to the notification
[pool release];
[NSThread exit];
</font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">It's not necessary to call exit on a thread. Just let the function end, and the thread will exit.
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif">
}</strong></font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">The reason you're getting leaks is that the NSThreadWillExitNotification is being run in the thread that's ending, not in the main thread. Objects that you autorelease in the method called by that notification are thus leaking. I wouldn't be surprised if you had some synchronization issues too. There's no quick fix for that. Multithreading is extremely tricky.

-Peter
     
seppak  (op)
Fresh-Faced Recruit
Join Date: Dec 2001
Location: Wisconsin
Status: Offline
Reply With Quote
Jul 9, 2002, 12:34 PM
 
Thanks, that solved the problem. I didn't know that the notification would only be sent in the current thread. Now that I know this, I just use a timer to periodically check if the move has been found and everything works fine...Thanks for the help. As for the extra retains and releases, I just like to follow a pattern. ie. If I get an array autoreleased I will always retain it and release it when I am done, regardless of the autoreleasepools.

Some more questions:
If (moves != nil) && ([moves count] &gt; 0)....If you send a count message to nil, how do you know the value that you will get back? Will it always just be 0(nil)?

Notice when you run it you get warnings in the CheckersPiece class about CheckersGame not responding to [pieceAtRow....] even though it exits. If I try to include the file, I get an error. How can I get around this? I tried to say just @class CheckersGame; but this didn't help...

<a href="http://homepage.mac.com/seppak/Checkers.dmg.gz" target="_blank">Here</a> is the actually program with the threads that work just disregard the terrible graphics...As for how well the computer plays, you will probably want to play against adult. It plays fairly well but is still beatable.

<small>[ 07-09-2002, 01:36 PM: Message edited by: seppak ]</small>
     
Junior Member
Join Date: Mar 2001
Status: Offline
Reply With Quote
Jul 9, 2002, 06:41 PM
 
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif">Originally posted by seppak:
<strong>Thanks, that solved the problem. I didn't know that the notification would only be sent in the current thread. Now that I know this, I just use a timer to periodically check if the move has been found and everything works fine...Thanks for the help. As for the extra retains and releases, I just like to follow a pattern. ie. If I get an array autoreleased I will always retain it and release it when I am done, regardless of the autoreleasepools.
</strong></font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">Ok.

</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif"><strong>

Some more questions:
If (moves != nil) && ([moves count] &gt; 0)....If you send a count message to nil, how do you know the value that you will get back? Will it always just be 0(nil)?

</strong></font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">Yes, the value you get back will always be 0 (in an integer or floating point context) or nil (in a pointer context). I use this a great deal; for example, in setter methods, you can release or autorelease your old objects even if they have never been initialized, because in that case they are guaranteed to be nil and the release message will do nothing. I don't know about the values of the fields of structs returned from a message to nil, but I wouldn't rely on them being anything in particular.

</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif"><strong>

Notice when you run it you get warnings in the CheckersPiece class about CheckersGame not responding to [pieceAtRow....] even though it exits. If I try to include the file, I get an error. How can I get around this? I tried to say just @class CheckersGame; but this didn't help...

</strong></font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">I don't see any warnings when you run it; are they perhaps compile time warnings? If so, you need to make sure you declared the pieceAtRow method in the CheckersGame class header, and that the CheckersPiece source file #imports that header.

</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">quote:</font><hr /><font size="1" face="Geneva, Verdana, Arial, sans-serif"><strong>

<a href="http://homepage.mac.com/seppak/Checkers.dmg.gz" target="_blank">Here</a> is the actually program with the threads that work just disregard the terrible graphics...As for how well the computer plays, you will probably want to play against adult. It plays fairly well but is still beatable.</strong></font><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">Looks good to me!

-Peter
     
Junior Member
Join Date: Jul 2001
Location: Mos Eisley Cantina
Status: Offline
Reply With Quote
Jul 10, 2002, 07:35 PM
 
I just downloaded the game, it's not too bad. The graphics could be improved, but it does play a decent game of checkers.

I played an interesting game against the adult player, which I won, but no pieces were captured by either myself or the computer. Neither player could move anymore. I don't play a lot of checkers, so this struck me as funny, because I never thought it could happen.

Improve the graphics a bit, and consider adding network play against a second player (distributed objects would be helpful), and this would be a decent piece of shareware.
     
seppak  (op)
Fresh-Faced Recruit
Join Date: Dec 2001
Location: Wisconsin
Status: Offline
Reply With Quote
Jul 11, 2002, 05:47 PM
 
I don't know how to do graphics so we are stuck with the ones I drew in GraphicConverter unless someone wants to update them <img border="0" title="" alt="[Wink]" src="wink.gif" /> . As for network play with distributed objects, I know nothing about it but it would probably be a good thing to learn...
     
   
Thread Tools
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Top
Privacy Policy
All times are GMT -5. The time now is 09:57 PM.
All contents of these forums © 1995-2011 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.7 © 2000-2011, Jelsoft Enterprises Ltd., Content Relevant URLs by vBSEO 3.3.2