CocoaDev

Edit AllPages

Hello all-

What I am trying to do: a) run some lengthy operations in the ‘background’ b) show a progress indicator to update the progress of the operation c) make sure that the GUI is still responsive and that the thread can be stopped/restarted

How I did it: a) I used code from the Anguish/Buck/Yacktman book “Cocoa Programming” example ‘ThreadExample’ b) uses Distributed Objects to setup additional threads that allow for talking between the multi-thread and the ‘main’ thread

some code: Controller class-

@protocol ApplescriptController // the server object will send the controller (parent) these messages

// intended for progress displays

@interface iLHThreadediTunesController : NSObject { id setInterface; } @end

@implementation iLHThreadediTunesController

server object class-

@protocol ApplescriptMethods // the applescript controller (parent) calls these to control the applescript object

@interface ApplescriptObject : NSObject { int amountDone, tag; BOOL paused, running, suppressProgress; id parent; } // you call this to spawn a new thread

@interface ApplescriptObject(_private) // main thread calls this to set up a new server; called by method above // this runs in the new thread.

@implementation ApplescriptObject // sets up a DO connection in the main thread and then kicks off a // new thread with a brand new server object in it.

// finish setting the the DO connection to the main thread // and set up a run loop for this thread. The main thread // will call us with requests to process data which the run // loop will pick up. If there’s nothing to do, the run // loop will block and no CPU time will be wasted.

server object subclass

@interface iLHThreadedSetApplescriptInterface : ApplescriptObject { } @end

@implementation iLHThreadedSetApplescriptInterface // overridden so that we suppress progress by default

// **’ this is the operation that is stalling the GUI !!! **’ // // all it is doing is taking a bunch of images and creating a pdf from them

What is happening: a) the threads are started up properly (I checked with Thread Viewer) b) the processes are running in the background thread (again, checked with Thread Viewer) c) but, the GUI is stalled and the pin wheel shows up. By using Spin Control, I verified that it is the background thread that is causing the problem

Can anyone verify that I am doing this properly? Should my GUI be stalled? Is there a better way to do this?

Thanks in advance


You are going to have to tell us more. I just downloaded and built the example from “Cocoa Programming” and it worked great. The GUI was responsive all the time. However, I can’t help thinking it could be a much simpler example now that Apple has given us � performSelectorOnMainThread:withObject:waitUntilDone:
� performSelectorOnMainThread:withObject:waitUntilDone:modes:

Just update the progress bar in a method that you execute via -performSelectorOnMainThread:withObject:waitUntilDone: called from the worker thread. The worker thread can check the value of a shared variable periodically to see if the work should be canceled or not.

I just spotted the problem. The AppKit is not thread safe, and you are using the AppKit from the main thread and the worker thread. You can’t use NSImage or NSPrintInfo or iLHBookletImageView (assuming is is a subclass of NSView) in your worker thread!

Why are you doing this is a sepearte THREAD ? Why not use an entirely seperate server application if you are going to use DO and/or AppleScript anyway ? A server application will have its own connection to Quartz and its own protected memory etc.

Multi-threaded programming is an insidious nightmare and should be avoided whenever possible.

See also SignalSafety, NotificationsAcrossThreads, UpdatingUIWhileBusyWithoutThreads, ThreadSafety, UpdatingDisplayDuringTimeConsumingTasks, NSTaskTermination, NSProgressIndicatorInMultithreadedDrawing, ProducersAndConsumerModel,

I recommend the TrivialThreads sample from developer.apple.com as a better (more current) sample from to base your project. BroadcasterDaemon is another relevant Apple sample.


Thanks for the response eveyone! As always, this site provides quick and useful responses. I have a lot to chew on here so I will post my solution when I come up with one…

-Ryan


I wouldn’t go so far as to say MT is a nightmare and should be avoided. However, I would not recommend Cocoa MT for beginners. It is the most complicated threading API to use that I have seen. Yes, I admit that methods such as performSelectorOnMainThread make it very easy to create an run threads. Communication between threads is very difficult in Cocoa. It is difficult because it isn’t well understood - Proxies, Connection Kits, run loops, more proxies, arg!. I don’t understand it that well and I am not going to release MT code that I don’t understand.

I suggest looking at some older and simpler MT APIs like pthreads. You can set up a simple producer-consumer model with a mutex and a container. It will run fast, be simple to code, and fairly foolproof.


Just to make it clear, you can set up a simple ProducersAndConsumerModel with an NSConditionLock and an NSArray — no need to delve into pthreads unless you want to. Also, the WorkerThread page is an attempt to provide a simple model for multithreading, again 100% Cocoa-based.