I need to run two threads simultaneously, but I am not getting how to do so.
I start thread:
[NSThread detachNewThreadSelector:#selector(MyNewThread:) toTarget:[CMyClass class] withObject:nil];
-(void)MyNewThread:(id)param{
NSAutoreleasePool *Pool = [[NSAutoreleasePool alloc] init];
NSString *strSwitcher = #"myCommand";
const char * cstrSwitcher = [strSwitcher UTF8String];
system(cstrSwitcher);
[Pool release];
}
and some other system command I want to send on other thread. When I send one system command prompt changes.(e.g. myCommand> ).
Now when I start another thread then that command only works when previous thread was stopped.
Anyone can help me??
By taking into account the info in your comment on the OP, I assume you want to call system() from multiple thread simultaneously.
Unfortunately, that cannot work because when you call system(), your application waits for a signal that is sent as soon as the child process exits. Because signals don't know anything about the threads in your application, system() cannot be run from multiple threads simultaneously.
Thanks for JeremyP to point into the direction of NSTask in the comments!
The alternative is to use the NSTask.
NSTask uses fork() to create a child process and calls waitpid() in the parent and execve() (or one of its siblings) in the child process. Using the macros defined in <sys/wait.h>, the child's return value is retrieved after it finishes. This way, multiple child process can be launched without blocking other threads. You can either do all that yourself, or just use the simple NSTask class.
I would suggest not using Hungarian notation (Windows picked that up back in the Win32 days, but dropped it in .NET) as that just complicates things. rename 'Pool' to 'pool', and 'strSwitcher' to 'switcher'. Now, just call system([switcher UTF8String]); instead of that extra variable. On top of this, remove the NSAutoreleasePool, and use the new #autoreleasepool { } definition, enclosing your code in it. Here's how it looks now.
- (void)myNewThread:(id)param {
#autoreleasepool {
NSString *switcher = #"myCommand";
system([switcher UTF8String]);
}
}
And if you'd like to switch to NSTasks to be able to run multiple executables, here's how it goes: (I also changed the method a bit.)
- (void)executeTaskAtPath:(NSString *)path withArguments:(NSArray *)arguments {
#autoreleasepool {
NSTask *task = [launchedTaskWithLaunchPath:path arguments:arguments];
[task waitUntilExit]; // This blocks the thread.
}
}
To find out if the task was terminated successfully, register for a NSTaskDidTerminateNotification at [NSNotificationCenter defaultCenter].
Related
Basic Setup
I use NSTask to run a process that optimizes images. This process writes output data to stdout. I use the readabilityHandler property of NSTask to capture that data. Here is the abbreviated setup:
NSTask *task = [[NSTask alloc] init];
[task setArguments:arguments]; // arguments defined above
NSPipe *errorPipe = [NSPipe pipe];
[task setStandardError:errorPipe];
NSFileHandle *errorFileHandle = [errorPipe fileHandleForReading];
NSPipe *outputPipe = [NSPipe pipe];
[task setStandardOutput:outputPipe];
NSFileHandle *outputFileHandle = [outputPipe fileHandleForReading];
NSMutableData *outputData = [[NSMutableData alloc] init];
NSMutableData *errorOutputData = [[NSMutableData alloc] init];
outputFileHandle.readabilityHandler = ^void(NSFileHandle *handle) {
NSLog(#"Appending data for %#", inputPath.lastPathComponent);
[outputData appendData:handle.availableData];
};
errorFileHandle.readabilityHandler = ^void(NSFileHandle *handle) {
[errorOutputData appendData:handle.availableData];
};
I then call NSTask like this:
[task setLaunchPath:_pathToJPEGOptim];
[task launch];
[task waitUntilExit];
(This is all done on a background dispatch queue). Next I examine the return values of NSTask:
if ([task terminationStatus] == 0)
{
newSize = outputData.length;
if (newSize <= 0)
{
NSString *errorString = [[NSString alloc] initWithData:errorOutputData encoding:NSUTF8StringEncoding];
NSLog(#"ERROR string: %#", errorString);
}
// Truncated for brevity...
}
The Problem
Approximately 98% of the time, this works perfectly. However, it appears that -waitUntilExit CAN fire before the readabilityHandler block is run. Here is a screenshot showing that the readability handler is running AFTER the task has exited:
So this is clearly a race condition between the dispatch queue running the readabilityHandler and the dispatch queue where I've fired off my NSTask. My question is: how the hell can I determine that the readabilityHandler is done? How do I beat this race condition if, when NSTask tells me it's done, it may not be done?
NOTE:
I am aware that NSTask has an optional completionHandler block. But the docs state that this block is not guaranteed to run before -waitUntilExit returns, which implies that it CAN begin running even SOONER than -waitUntilExit. This would make the race condition even more likely.
Update: Modern macOS:
availableData no longer has the issues I describe below. I'm unsure precisely when they were resolved, but at least Monterey works correctly. The approach described below is for older releases of macOS.
Additionally, with the modern Swift concurrency system in place and the new paradigm of "threads can always make forward progress", using semaphores like below should be a last resort. If you can, use NSTask's completionHandler API. I have no FORMAL guarantee that the readability handlers will complete before the completionHandler is called, but they seem to in practice, at least on modern macOS. Your mileage may vary.
Old Advice:
Ok, after much trial-and-error, here's the correct way to handle it:
1. Do not Use -AvailableData
In your readability handler blocks, do not use the -availableData method. This has weird side effects, will sometimes not capture all available data, and will interfere with the system's attempt to call the handler with an empty NSData object to signal the closing of the pipe because -availableData blocks until data is actually available.
2. Use -readDataOfLength:
Instead, use -readDataOfLength:NSUIntegerMax in your readability handler blocks. With this approach, the handler correctly receives an empty NSData object that you can use to detect the closing of the pipe and signal a semaphore.
3. Beware macOS 10.12!
There is a bug that Apple fixed in 10.13 that is absolutely critical here: on old versions of macOS, the readability handlers are never called if there is no data to read. That is, they never get called with zero-length data to indicate that they’re finished. That results in a permanent hang using the semaphore approach because the semaphore is never incremented. To combat this, I test for macOS 10.12 or below and, if I’m running on an old OS, I use a single call to dispatch_semaphore_wait() that is paired with a single call to dispatch_semaphore_signal() in NSTask’s completionHandler block. I have that completion block sleep for 0.2 seconds to allow the handlers to execute. That’s obviously a godawfully ugly hack, but it works. If I’m on 10.13 plus, I have different readability handlers that signal the semaphore (once from the error handler and once from the normal output handler) and I still signal the semaphore from the completionHandler block. These are paired with 3 calls to dispatch_semaphore_wait() after I launch the task. In this case, no delay is required in the completion block because macOS correctly calls the readability handlers with zero-length data when the fileHandle is done.
Example:
(Note: assume stuff is defined as in my original question example. This code is shortened for readability.)
// Create the semaphore
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
// Define a handler to collect output data from our NSTask
outputFileHandle.readabilityHandler = ^void(NSFileHandle *handle)
{
// DO NOT use -availableData in these handlers.
NSData *newData = [handle readDataOfLength:NSUIntegerMax];
if (newData.length == 0)
{
// end of data signal is an empty data object.
outputFileHandle.readabilityHandler = nil;
dispatch_semaphore_signal(sema);
}
else
{
[outputData appendData:newData];
}
};
// Repeat the above for the 'errorFileHandle' readabilityHandler.
[task launch];
// two calls to wait because we are going to signal the semaphore once when
// our 'outputFileHandle' pipe closes and once when our 'errorFileHandle' pipe closes
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
// ... do stuff when the task is done AND the pipes have finished handling data.
// After doing stuff, release the semaphore
dispatch_release(sema);
sema = NULL;
Create a semaphore with an initial value of 0. In the readability handlers, check if the data object returned from availableData has length 0. If it does, that means end of file. In that case, signal the semaphore.
Then, after waitUntilExit returns, wait on the semaphore twice (once for each pipe you're reading). When those waits return, you've got all of the data.
I have the following situation where I create a GCD dispatch queue and in it I schedule an NSStream to the current NSRunLoop, as is required in its specification for it to emit delegate events, and then I make the run loop for that thread run using [[NSRunLoop currentRunLoop run].
This generates three possible scenarios:
Create a serial queue in which an initial write message is sent through the stream and other write messages are only sent when there's a delegate callback from the NSStream object, as attempting to write new messages without respecting this pattern (this would be desirable) will fail as the queue is locked by the run loop running.
Create a concurrent queue in which messages can be written to the stream freely, as blocks sent to the queue will be executed concurrently with the block that's running the run loop. However, while it is desirable to make writing messages and the run loop running concurrent, it certainly is not desirable to have to blocks in the queue running concurrently attempting to write at the same time to the stream.
Create two queues -- one responsible for keeping the run loop alive and receive read-from-stream callbacks and another one for sending asynchronous write messages to the stream. This would seem ideal, however it seems that the NSStream documentation specifically states that one should not attempt to read/write to a stream outside the thread it is scheduled in.
Given these scenarios none of which are ideal, how to solve these problems?
Late to the party, but instead of using runloops you can set the desired dispatch queue for your streams directly using
void CFReadStreamSetDispatchQueue(CFReadStreamRef stream, dispatch_queue_t q);
void CFWriteStreamSetDispatchQueue(CFWriteStreamRef stream, dispatch_queue_t q);
Where CFReadStreamRef can take a bridged NSInputStream and CFWriteStreamRef a bridged NSOutputStream. This way you don't have to schedule or unschedule runloops at all and your streams will run in the background.
Snippet from this Apple sample code:
CFReadStreamSetDispatchQueue((__bridge CFReadStreamRef) self.inputStream, self.queue);
CFWriteStreamSetDispatchQueue((__bridge CFWriteStreamRef) self.outputStream, self.queue);
In Swift, you can just directly call the functions:
CFReadStreamSetDispatchQueue(inputStream, streamQueue)
CFWriteStreamSetDispatchQueue(outputStream, streamQueue)
As you noted from the docs, when you have a run-loop-based API like NSStream, the general expectation is that all interaction with that object will occur on the thread that owns the run loop on which it's scheduled. I'm not sure there's really any benefit to mixing these two idioms (GCD and run loops) when it comes to working with NSStream.
Other than the main queue, GCD has no concept of thread-affinity, so unless the run loop you schedule the NSStream on happens to be the main thread run loop, there's no good way to use dispatch_async to schedule blocks for execution on that thread.
At the risk of stating the obvious, you should probably just use the standard methods for scheduling methods on other threads. -performSelector:onThread:withObject:waitUntilDone:modes: is the most obvious. If your confusion is that you want to work with blocks, it helps to know that heap-allocated blocks can be treated like Objective-C objects and implement the -invoke selector just like NSInvocations do. A trivial example relevant to your question might look like this:
#interface AppDelegate ()
{
NSThread* bgthread;
}
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Basic loop to get the background thread to run until you call -cancel on it
dispatch_block_t threadMain = [^{
NSThread* thread = [NSThread currentThread];
NSParameterAssert(![thread isMainThread]);
NSRunLoop* currentRunLoop = [NSRunLoop currentRunLoop];
NSPort* port = [NSPort port];
// If we dont register a mach port with the run loop, it will just exit immediately
[currentRunLoop addPort: port forMode: NSRunLoopCommonModes];
// Loop until the thread is cancelled.
while (!thread.cancelled)
{
[currentRunLoop runMode: NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]];
}
[currentRunLoop removePort: port forMode: NSRunLoopCommonModes];
[port invalidate];
port = nil;
} copy];
// Start the thread
bgthread = [[NSThread alloc] initWithTarget: threadMain selector: #selector(invoke) object: nil];
[bgthread start];
// Fetch the runloop, so you can schedule an NSStream on it...
__block NSRunLoop* runloopForStream = nil;
dispatch_block_t getrunloop = [^{
runloopForStream = [NSRunLoop currentRunLoop];
} copy];
// Dispatch synchronously, so that runloopForStream is populated before we continue...
[getrunloop performSelector: #selector(invoke) onThread: bgthread withObject: nil waitUntilDone: YES];
// Schedule your stream, etc.
NSOutputStream* mystream = ...; // Your code here...
[mystream scheduleInRunLoop: runloopForStream forMode: NSDefaultRunLoopMode];
// Then later, when you want to write some data...
NSData* dataToWrite = [NSMutableData dataWithLength: 100];
dispatch_block_t doWrite = [^{
[mystream write: dataToWrite.bytes maxLength: dataToWrite.length];
} copy];
// Dispatch asynchronously to thread
[doWrite performSelector: #selector(invoke) onThread: bgthread withObject: nil waitUntilDone: NO];
}
#end
Note that the -copy of the blocks is necessary to get them copied to the heap, otherwise they'll be deallocated when the declaring method goes out of scope.
I am having a gui/threading related problem in developing a cocoa user interface. The application is designed like this:
Main Thread (#1): parses arguments, loads plugins, etc.
Gui thread (#?): launches the gui, handles events, etc. Its the gui thread.
The Cocoa framework is non-thread safe, but enforces one rule, the GUI must run on the main thread. A assertion is used to check this. To try to go around this I implemented the run method myself (code below) following this - http://cocoawithlove.com/2009/01/demystifying-nsapplication-by.html - guide. But I am missing something. A window is opened, but stays blank (completely white). Although if I make the call in the main thread it works perfectly.
So basically I need to figure out what's missing.
- (void)run
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self finishLaunching];
shouldKeepRunning = YES;
do
{
[pool release];
pool = [[NSAutoreleasePool alloc] init];
NSEvent *event =
[self
nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue:YES];
[self sendEvent:event];
[self updateWindows];
} while (shouldKeepRunning);
[pool release];
}
- (void)terminate:(id)sender
{
shouldKeepRunning = NO;
}
Don't. This approach will never work. Even if you fix your current problem (the window not drawing) you'll immediately run into another obscure, impossible-to-fix problem, and another, and another. Cocoa expects the GUI thread to be the main thread, end of story.
Do all in the background thread except updating the GUI. I see that you have only a line where you need to update the GUI. So do it the way you're doing it, except that you execute all GUI updates in the main thread:
dispatch_async(dispatch_get_main_queue(), ^
{
[self updateWindows];
});
Now I don't know what's updateWindows, I assumed that this wouldn't create a race condition.
Why not reverse the problem? Have the main thread spawn a thread (let's call this the app thread), then block before spawning the GUI. The app thread will parse arguments, load plugins, etc. After it's initialization is done, the app thread will signal the main thread to go ahead and launch the GUI.
I'm testing the HTTPFileUploadSample now. Because I want to use it to create a type of command tool line program, so i call the method in the main() function, like this:
int main (int argc, const char * argv[])
{
#autoreleasepool {
Uploader *upl = [Uploader alloc];
[upl initWithURL:[NSURL URLWithString:#"http://localhost/uploader.php"]
filePath:#"/test.txt"
delegate:upl
doneSelector:#selector(onUploadDone)
errorSelector:#selector(onUploadError)];
//[[NSRunLoop currentRunLoop] run];
}
return 0;
}
I found it can create the connection and post request normally, but it can not finish the connection, because it do not call those delegate methods(connection:didReceiveResponse: or connection:didReceiveData: or connectionDidFinishLoading:) at all.
So I call the method [[NSRunLoop currentRunLoop] run] to run loop (as the comment in codes), then everything is ok. I do not know why. Can anybody give me some explanation? Thx!
The runloop is a big event handler infinite loop (well, infinite until it's stopped). It watches various sources and when they generate events it dispatches those events to listeners. This is a very effective way to manage asynchronous operations on a single thread.
NSURLConnection (and many other things in Cocoa) rely on the runloop for their processing. If nothing runs the runloop, then the events aren't processed.
Consider the following main() method which you would find most iPhone applications:
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
In every iPhone app that I've run in Simulator with these (including several sample projects provided by Apple), the thread never exits UIApplicationMain() and any remaining code in main() is never executed. Is this expected behavior?
I have verified that statements after UIApplicationMain() never run by stepping through the code with a debugger. When the user stops an application (by hitting the "Home" button, for example), the resulting stack trace shows that [UIApplication _terminateWithStatus:] is eventually called. This function calls your application delegate's applicationWillTerminate: method. Once that finishes, [UIApplication _terminateWithStatus:] seems to kill/exit the thread.
Can someone confirm that this is how main() is supposed to work, or at least confirm the same behavior on their machine?
The original question was: "Why doesn’t an iPhone app’s main() function ever get a chance to finish?"
Short Answer: Because UIApplicationMain() is coded such that it never returns.
After doing several tests in Simulator and on the device, and asking another developer to do the same tests, I have confirmed that UIApplicationMain never returns. When the user terminates an application normally by hitting the Home button, The program ultimately terminates inside an unpublished UIApplication method called _terminateWithStatus. This method calls exit(0).
This behavior matches that of the NSApplicationMain function (which is AppKit/Cocoa version of the UIApplicationMain function). The documentation for NSApplicationMain() clearly states that it will never return.
I have submitted a bug (6600198) to Apple requesting that the official documentation (and Xcode template for main.m) be corrected to state that UIApplicationMain() never returns. While this is not a functional problem, the current template and docs are misleading.
Thanks to everyone for all the input and brainstorming!
Try:
int main(int argc, char *argv[])
{
NSLog(#"Step 0");
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(#"Step 1");
int retVal = UIApplicationMain(argc, argv, nil, nil);
NSLog(#"Step 2");
[pool release];
NSLog(#"Step 3");
return retVal;
}
It may be that the release of the pool is preventing further logging in which case you'd get step 2 but not step 3.
If step 2 isn't being printed, then it's almost certainly something wrong with UIApplicationMain - there's a chance that it doesn't return so put NSLog statements (step 1.1, Step 1.2, ...) at various points within it and run to find the last message logged.
Keep drilling down (Step 1.7.1, 1.7.2, .... 1.7.6.3.2, ...) - eventually, you'll track down the exact line (however deep in the call hierarchy) when the log messages stop being logged and that line will be your culprit (either "turning off" logging or exiting without returning normally).
One further snippet I found on the web:
=====
When you use this line:
int retVal = UIApplicationMain(argc, argv, #"MyApp", #"MyApp");
The first MyApp is your main app delegate class. The second is the class to where SpringBoard sends touch notifications.
Also, if you are using the SDK, and have a main nib defined in the Info.plist, then you can leave the call as:
int retVal = UIApplicationMain(argc, argv, nil, nil);
as all that will be covered when you create your xibs.
=====
Now I don't know enough about iPhone development (specifically xibs) to know what that last bit even means (or if you've set it up correctly) but it sounds like another phase of compilation.
However, my first thought from reading that is that Springboard will call your delegate class when the buttons are pressed to ask you to do something (like shut down gracefully). If it can't ask you (i.e., no delegate), it's probably within its rights to shut you down as it sees fit, such as with [UIApplication _terminateWithStatus:].
In the Windows world, you would probably send off a quit message to the main window but, as I say, iPhone development may be different.
Still, it's an avenue to investigate. I'd be interested in seeing what calls were made to a delegate if you provided one. The code included with the snippet above had this:
#implementation MyApp
- (void) applicationDidFinishLaunching:(id)unused {
rect = [ UIHardware fullScreenApplicationContentRect ];
rect.origin.x = 0.0f;
rect.origin.y = 0.0f;
window = [ [ UIWindow alloc ] initWithContentRect: rect ];
[ window makeKeyAndVisible ];
view = [ [ MyAppView alloc ] initWithFrame: rect ];
[ window setContentView: view ];
}
- (void) dealloc {
[ window release ];
[ view release ];
[ super dealloc ];
}
So maybe a delegate with dealloc() is the secret to getting it to exit back to main(). Why don't you give that a shot? It may get you closer to your goal even if it doesn't solve the core problem.
After [pool release] there is nothing to log to?
trying using fprintf and see what happens
int main(int argc, char *argv[])
{
/*
...
same as above
...
*/
[pool release];
char file_name = "/tmp/log"
FILE *file = fopen(file_name, "w");
fprintf(file_name, "END\n");
}
and tell us what happens
I also thought the easiest way to check was to set a break point right at the return
in gdb do
b main.c:x
where x is the line number of the return statement
After calling the UIApplicationMain function your application launches (establishing a runloop, etc) and all work should then be done outside the context of main (if you need it to run in main, do it before that point). When quitting an application it is generally more efficient to allow the OS to do memory cleanup.
I have that not return experience too. And have set break points to verify exactly like Clint said.
wisequark has a good point.
great topic. makes me feel more comfortable that i am not the only one who has the question.