Re: Am I using NSConditionLock correctly?
Re: Am I using NSConditionLock correctly?
- Subject: Re: Am I using NSConditionLock correctly?
- From: jkp <email@hidden>
- Date: Wed, 12 Oct 2005 08:52:14 +0100
You can check the state of your threads by pauding operations at some
point in the debugger (perhaps when you are waiting for the message
to arrive?) and pull down the thread menu. You can then get a
backtrace for each thread which should show you where they are, if
they are deadlocked etc.
Jamie
On 12 Oct 2005, at 03:29, Steve Weller wrote:
The latest update is that I got rid of the lock entirely and it
still does not work. I suspect that I am the victim of deferred
action, but need to experiment a little to confirm that.
I think that my message to stop calculation is getting deferred.
Control returns from the message send and my method then waits for
calculation to stop -- which it never does. If I remove the lock
and let execution continue and fall off the end of the method,
then the message arrives and calculation stops. At least this is
what the NSLog messages are telling me. At this point I am not sure
if I trust them since *they* could be getting queued or blocked
somewhere.
All of this is happening in -dataOfType:error. Could it be that the
way I get to this point is causing my messages to be deferred? Am I
even on the main thread like I think I am?
On Oct 11, 2005, at 1:04 AM, jkp wrote:
On 10 Oct 2005, at 22:57, Steve Weller wrote:
On Oct 10, 2005, at 1:37 PM, jkp wrote:
The way you have described it, you are making your main thread
sleep on the condition lock whilst your worker does the
work...blocking in the process. the simple question i ask you
is...what does this buy you?
My main thread has to wait for the worker thread to get into a
known state so I can save my objects to disk. So I need to block
my main thread until the worker thread says "I've stopped now".
It is a short amount of time -- short enough that the interface
will not suffer during the block.
You might as well just do the calculation on the main thread and
simplify your life! If you have the main thread sleep on the
lock whilst the worker does its work you are still blocking, so
you achieve the same thing.
The main thread keeps the GUI alive, so it cannot sleep under
normal circumstances. And this whole project is an exercise in
using a computationally-intensive worker thread.
surely if you want to keep the GUI "alive" it needs to be able to
respond no? It will not respond if you have it sitting on a
lock. I understand you want to save data when it is in a known
good state - so why not engineer things so the rest of your
program doesnt touch that data whilst the worker is busy with it,
and then the worker can signal to you when it is done using one of
the methods i suggested.
I recently implemented worker class to use throughout my current
application and i learnt a lot in the process. A condition lock
is a great way to go since it allows you to have your workers
sleep efficiently and for you to exact granular control on them
when you need their services.
The way you describe is interesting. I am currently starting and
stopping my worker thread by creating and destroying it. But I
have reasons for doing that: I need to be able to throw away its
state and give it a new state to continue calculating with. It's
easier to throw away the whole thread and start a new one. I can
see how condition locks can be used to signal a thread what to do
and read its state back.
I took this a step further actually an implemented a custom queue
(in the form of a CFArray). A set of predefined instructions are
passed via the queue to the worker, and it runs its own special
loop to process the instructions. On each iteration it checks the
lock (and can also check at other points during the threaded
routines)....the lock tells the worker if it should continue
worker, stop, start work or die etc....the Queue itself holds the
details of what is to be done (an invocation is the most common
content of the queue).
I think you could do with defining a set of conditions that
might apply to your thread at any point during its life cycle.
Maybe something like NOWORK, WORKPENDING, DATAPENDING etc...You
can use these to notify the worker what it needs to do. The
worker can do its thing and when it is done you have a choice of
ways to send data / notify the main thread that things are
finished. My favorite is NSObject's
performSelectorOnMainThread:withObject:waitUntilDone: method.
You can use this to call a routine on the main thread and if you
want, wait until it is finished before your worker continues on
its way. This way your main thread can carry on accepting user
input etc, but each time it returns to its runloop it gets a
chance to process a pending request from the worker to perform a
selector.
I use that to update my GUI: progress bars etc. and to avoid
having to lock umpteen things. But I am actually finding the
synchronous nature of the call limiting. Not only that but async
calls to main thread methods are secretly synced up somewhere to,
so thwarting some other things I have tried.
If you mean they dont arrive as you expect them to, that is
because they are arriving on an NSPort of some kind. This as you
probably know is another way of communicating between threads
which is nice in some ways, but it has its limitations - namely
that the queue of instructions that can arrive on the thread
cannot be controlled with any precision - it is of a fixed length
so will reject instructions after a certain point, and also if you
have more than one port you cannot predict the order that messages
will arrive in. My second iteration had used ports exclusively,
but i found them too hard to control.
Another way you could do it would be to use the condition lock
to signal you have data, and maybe use a timer to check the lock
from the main thread - again, this way you dont lock the main
thread, but when the timer fires and there is data, the main
thread does the right thing. I dont like this method myself
since it is basically polling, but that would be one way you
could use the condition lock in this way if you wanted to.
Yes, I am desperately trying to avoid poll/sleep, but may have to
go that way if all else fails.
These are just some thoughts and ideas, but i think you could do
with working out exactly what you want your worker thread
implementation to be capable of, and then perhaps write a small
test app that proves that it can do these things as you want.
I'd also take time to stress test the classes you write since
you will be suprised what problems can arrise that you hadnt
thought of.
I'm guilty of lack of design forethought and experimentation. But
with good reason: I have no thoughts to put in the fore, since I
am learning this as I go along, and for experimentation: this is it.
If its any comfort it took me 3 iterations to get a pair of
classes that do the job for me and that i am happy with.
Multithreading is a tough topic so dont be suprised if you need
to go back and rehash your design several times before you get
something that works for you.
I'm on number three right now I think. What surprises me is that
multithreading is much harder than multiprocessing and/or
reentrant interrupt-driven code. It's slippery, but not entirely so.
My next attempt is to do exactly what I have been doing but with
a global (static) lock. This should circumvent all the swizzling
and whatever is syncing for me I hope.
Im not sure if this is the way to go. A condition lock is much
more useful because you can convey state as well as availibility.
Im still not clear on why you think it is worth offloading work to
the worker thread whilst leaving the main thread blocking - the
interface is not going to "stay alive" instead it will freeze
which is surely not what you want.
Multithreading is indeed a darn hard exercise, since it is almost
like returning to the bad old days of an unprotected shared memory
space used by mutliple processes (in this case threads). to say
that keeping everything valid and in sync is an art would be an
understatement!
Jamie
--
Watch me learn Cocoa http://homepage.mac.com/bagelturf/
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden