Re: Thread and Return key strangeness
Re: Thread and Return key strangeness
- Subject: Re: Thread and Return key strangeness
- From: email@hidden
- Date: Tue, 07 May 2002 17:45:46 -0700
Lorenzo Puleo wrote:
|I image APIs like
|session = [NSApp beginModalSessionForWindow:previewWindow];
|or showing an incremental "Items to do" value like
|[consTaskComment setObjectValue:stringItemsToDo];
|or showing a progressBar increasing its value
|could block the Thread too;
|
|If so, I would be really surprised.
|Since after the call detachNewThreadSelector
|all the following lines have been executed immediately, how could I solve my
|trouble?
|
|
|I have to do:
|Disable all the buttons
|{
|Start a loop which scans inside a long NSArray.
|If an error occurred I have to show a modal dialog asking for continuing or
|stopping. The modal dialog is complex. There are a lot of variable objects.
|At each item scanned I have to increment a NSText field and a progress bar.
|The use should be able to stop the task clicking on the "Stop" button.
|}
|Enable all the buttons
|
|
|I have done that very well without threads, but I was not able to stop the
|task clicking on the "Stop" button. So I introduced the threads, ...and the
|trouble above.
|Please, any assistance/sample-code is appreciated. Thanks.
|Please note that the things are much much complex than I am describing here.
You don't know the half of it. What you're trying to do is full-fledged multithreading with synchronization and inter-thread communication (to really pile on the jargon), and that can get rather tricky. Since one of the threads you want to include is the UI thread, things could get even trickier.
First off, you'll really need some background on the whole "multithreading" thing. Go to <
http://developer.apple.com/techpubs/macosx/Cocoa/TasksAndConcepts/ProgrammingTopics/Multithreading> (at /Developer/Documentation/Cocoa/TasksAndConcepts/ProgrammingTopics/Multithreading if you have the developer documentation installed).
I'd suggest you look into "distributed objects", which is basically a way for two objects to communicate, each doing its thing in its own thread, and is the officially-recommended way to have threads interact. The two objects are connected such that if you call a method using one object, the same-named method of the other is what's actually executed, in a different thread. (The caller is stopped until the method returns.) The only uncertainty I have is whether there's a problem with the UI thread being one of the threads involved. Any other thread can stop dead in its tracks with no real harm; the UI thread can't.) You can write most of your code very much the way you'd have written it without threads. (There'll still be some places where you need to take extra care to keep the threads from getting in each other's way.)
Apple has sample code using distributed objects available, at <
http://developer.apple.com/samplecode/Sample_Code/Processes/TrivialThreads.htm> and <
http://developer.apple.com/samplecode/Sample_Code/Processes/SimpleThreads.htm>.
If it turns out distributed objects won't work, then you'd have to do all the thread synchronization yourself. Likely, the work thread would have to post ApplicationDefined events to get the UI updated as things change. The UI code would have to be able to stop the work thread, which would best be done using locks.
Without distribued objects, the work thread would probably look like this:
- (void) workThread: (id) junk
{
lock(stoppedByUser);
stoppedByUser = NO;
unlock(stoppedByUser);
while(unprocessed items remain)
{ BOOL stop;
lock(stoppedByUser);
stop = stoppedByUser;
unlock(stoppedByUser);
if(stop)
break;
if(doSomethingUseful(next item))
postEvent(nextItemDoneEvent);
else
{ postEvent(itemDidntWorkEvent);
waitForDialogToGoAway();
}
}
postEvent(workFinishedEvent);
// You don't need to do anything but exit your method when
// your thread is done. NSThread takes care of the rest.
}
The main (UI) thread:
- (void) startWorkThread: (id) sender
{
[buttonList disableAllButtons];
[NSThread detachNewThreadSelector: @selector(workThread:) withObject: nil];
}
- (void) handleNextItemDoneEvent
{
[progressBar indicateProgress];
}
- (void) handleItemDidntWorkEvent
{
displayModalDialog();
// The last action of the dialog (done when the user clicks "OK")
// would be to notify the work thread that the dialog has gone away
// (the details of which would only confuse matters here).
}
- (void) handleWorkFinishedEvent
{
[buttonList enableAllButtons];
}
- (void) userClickedStopButton: (id) sender
{
lock(workThread->stoppedByUser);
workThread->stoppedByUser = YES;
unlock(workThread->stoppedByUser);
}
There's a lot of detail swept under the rug here. For example, posting and handling the various application-defined events isn't as simple as I've made it appear. (On looking at this, if it actually does everything you need done, it might be simpler to do it this way than to use distributed objects. The only way to tell, really, is to try.)
All those lock() and unlock() calls are necessary, to keep the two threads from trying to use the stoppedByUser variable at the same time. Only one thread can lock the variable at a time; if the other thread tries to, it's stopped until the first thread unlocks the variable again.
You have set for yourself a decidedly nontrivial task, but one you *will* learn a lot from. The key thing to remember is that all your threads are running at the same time, which means that anything shared by more than one thread has to be guarded the way stoppedByUser was, or you could get really strange (and *very* hard to debug) problems.
Glen Fisher
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.