On Feb 4, 2009, at 4:49 AM, Oleg Krupnov wrote:
I use an NSTask to collect system info from system_profiler. Because it takes a while to complete, I launch that task in a separate thread, to avoid UI from freezing.
Both NSTask and NSFileHandle provide asynchronous interfaces, so it is not necessary to use a separate thread.
- (void)systemProfilerThread:(id)ignored { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString *configuration = nil; NSPipe* inputPipe = [NSPipe pipe];
You do nothing with inputPipe, so you should just get rid of it. If you want the task to not inherit your standard input, do [scriptTask setStandardInput:[NSFileHandle fileHandleWithNullDevice]].
NSPipe* outputPipe = [NSPipe pipe]; NSTask* scriptTask = [[[NSTask alloc] init] autorelease]; [scriptTask setLaunchPath:@"/usr/sbin/system_profiler"]; [scriptTask setArguments:[NSArray arrayWithObjects:@"-detailLevel", @"mini", nil]]; [scriptTask setStandardOutput:outputPipe]; [scriptTask launch]; [[inputPipe fileHandleForWriting] closeFile]; configuration = [[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding] autorelease]; if (!m_isCanceled) { [m_target performSelectorOnMainThread:m_action withObject:configuration waitUntilDone:NO]; } [pool drain]; } The problem is, according to the Leaks tool, is that there's a memory leak in -systemProfilerThread. The leak disappears if I launch the task in the main thread.
You don't say what is leaking or where it was allocated from.
I've read in docs that NSTask is NOT thread safe, but does it also apply to the above case, when the NSTask object is created and released within a single thread, though not the main thread? If NSTask cannot be used this way, then which way I should use it?
Create and launch the task from the main thread. Register for the task termination notification, if you're interested.
Also register for notification of read-to-end-of-file completion on the output file handle, and invoke - readToEndOfFileInBackgroundAndNotify on it. In the handler for that notification is where you can decode/parse the data.
After you have registered for these notifications and launched the task, return immediately. Don't block waiting for either the task to terminate or data to arrive from the file handle.
Also, what puzzles me is why, first and foremost, the main thread is blocked until the task is complete? I do not call wait -waitUntilExit. I would expect that the main thread is not blocked, but I receive the NSTaskDidTerminateNotification, but it does not happens with the code above.
I assume you mean the main thread is blocked if you _don't_ detach a separate thread, right? In that case, it's because you're using - readDataToEndOfFile, which is synchronous. It doesn't return until it has read to the end of the output from system_profiler -- that is, when system_profiler terminates and closes its standard output.
Also, where are you registering for NSTaskDidTerminateNotification? I don't see it above. In any case, regardless of on which thread you register for that notification, I would expect it to be posted on the thread which created the NSTask. Although notifications are not normally passed through the run loop, this particular notification is the result of the framework "noticiing" that the task has completed (an event which is, of course, external to your program and the framework's direct knowledge). In order to notice that, the framework needs the run loop of the thread to run. You never run the run loop for your thread in the code above.
I suspect, in fact, that that's the cause of the memory leak. The framework had some housekeeping to do that relies on the run loop running.
Cheers, Ken _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com