thread protocol modifiers

  • I've been trying to chase down a problem with my thread for sometime
    and I think
    I've found the problem with why I can't click on my interface even though I
    have a thread processing my data in the background ... so I have a few
    questions about protocol modifiers which I'm looking at as the culprit.

    #1) I have a class method written 3 times. Once in the class @interface,
    once as a @protocol method in the same file, and once in the implementation
    file when defining the method.

    I couldn't find this in the docs so my question is, when declaring a
    protocol modifier, must they all three say (oneway void) to be valid or does
    one of them override them all? I don't understand it, but it seems to me the
    @interface declaration is useless other than suppress a few warnings and
    make the class blueprint easier to read. Maybe someone can correct me on
    that. I think I had to put it in all three places for this to work, but I'm
    not sure if that's correct.

    #2) I make 3 calls to my server thread in sequence, so I marked all 3 as
    (oneway void). After doing this I was able to click on a button in my GUI
    while the thread was running, so I think the GUI was blocking w/ the default
    (inout void) ... at least I think that's the default.

    However my problem now is that with all three marked as (oneway void)
    (sending async msgs), message #2 requires a few seconds to complete while
    message #3 depends on message #2 before it can start, yet msg #3 is done
    before msg #2 can finish. I've also seen once where they arrived out of
    order.

    // from the client

    [server sendMsg1];

    [server sendMsg2];

    [server sendMsg3];

    Is there another way to call asynchronously, yet guarantee that the messages
    arrive in order? Or someway to call w/o the GUI blocking for a server
    message return?
  • >
    > However my problem now is that with all three marked as (oneway void)
    > (sending async msgs), message #2 requires a few seconds to complete
    > while
    > message #3 depends on message #2 before it can start, yet msg #3 is
    > done
    > before msg #2 can finish. I've also seen once where they arrived out
    > of
    > order.
    >
    >
    > // from the client
    >
    > [server sendMsg1];
    >
    > [server sendMsg2];
    >
    > [server sendMsg3];
    >
    >
    > Is there another way to call asynchronously, yet guarantee that the
    > messages
    > arrive in order? Or someway to call w/o the GUI blocking for a server
    > message return?

    You can use :
    - NSConnection/NSPorts ( http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/ar
    ticles/SocketComm.html#/

    /apple_ref/doc/uid/TP40001479 )
    - YAMessageQueue (10.4-): http://www.2pi.dk/tech/cocoa/message_queue.html
    - NSOperation/NSOperationQueue (10.5+) :
    - [NSObject performSelector:onThread]/[NSObject
    performSelectorInMainThread:] (10.5+);

    :: marcelo.alves
  • -performSelectorInMainThread: certainly predates Leopard…? I distinctly
    remember using it back in the 10.2/10.3 days.

    <marcelo.alves...> wrote:
    >>
    >> However my problem now is that with all three marked as (oneway void)
    >> (sending async msgs), message #2 requires a few seconds to complete
    >> while
    >> message #3 depends on message #2 before it can start, yet msg #3 is done
    >> before msg #2 can finish. I've also seen once where they arrived out of
    >> order.
    >>
    >>
    >> // from the client
    >>
    >> [server sendMsg1];
    >>
    >> [server sendMsg2];
    >>
    >> [server sendMsg3];
    >>
    >>
    >> Is there another way to call asynchronously, yet guarantee that the
    >> messages
    >> arrive in order? Or someway to call w/o the GUI blocking for a server
    >> message return?
    >
    >
    > You can use :
    > - NSConnection/NSPorts (
    > http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/ar
    ticles/SocketComm.html#//apple_ref/doc/uid/TP40001479

    > )
    > - YAMessageQueue (10.4-): http://www.2pi.dk/tech/cocoa/message_queue.html
    > - NSOperation/NSOperationQueue (10.5+) :
    > - [NSObject performSelector:onThread]/[NSObject
    > performSelectorInMainThread:] (10.5+);
    >
    >
    > :: marcelo.alves
  • I'm developing on 10.4 and have already implemented my thread using mach
    ports as your first link shows, this is how my client sends the msgs to my
    server thread.

    However, my client is blocking when the msgs are sent to the server unless I
    use the protocol modifiers (like oneway) on the thread, which then give me a
    different problem.

    On Jan 4, 2008 7:38 PM, <marcelo.alves...> wrote:

    >>
    >> However my problem now is that with all three marked as (oneway void)
    >> (sending async msgs), message #2 requires a few seconds to complete
    >> while
    >> message #3 depends on message #2 before it can start, yet msg #3 is
    >> done
    >> before msg #2 can finish. I've also seen once where they arrived out
    >> of
    >> order.
    >>
    >>
    >> // from the client
    >>
    >> [server sendMsg1];
    >>
    >> [server sendMsg2];
    >>
    >> [server sendMsg3];
    >>
    >>
    >> Is there another way to call asynchronously, yet guarantee that the
    >> messages
    >> arrive in order? Or someway to call w/o the GUI blocking for a server
    >> message return?
    >
    >
    > You can use :
    > - NSConnection/NSPorts (
    > http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/ar
    ticles/SocketComm.html#/

    > /apple_ref/doc/uid/TP40001479 )
    > - YAMessageQueue (10.4-): http://www.2pi.dk/tech/cocoa/message_queue.html
    > - NSOperation/NSOperationQueue (10.5+) :
    > - [NSObject performSelector:onThread]/[NSObject
    > performSelectorInMainThread:] (10.5+);
    >
    >
    > :: marcelo.alves
    >
  • Then what's the point of using ports to communicate over if I went to using
    performSelectorInMainThread? Besides, I'm going from the client (main
    thread) to the server (NSThread).
    Maybe I'm doing something all wrong, but my code is very, very similar to
    what's in the apple thread communication docs.

    On Jan 4, 2008 7:48 PM, John Stiles <JStiles...> wrote:

    > -performSelectorInMainThread: certainly predates Leopard…? I distinctly
    > remember using it back in the 10.2/10.3 days.
    >
    >
    > <marcelo.alves...> wrote:
    >>>
    >>> However my problem now is that with all three marked as (oneway void)
    >>> (sending async msgs), message #2 requires a few seconds to complete
    >>> while
    >>> message #3 depends on message #2 before it can start, yet msg #3 is
    > done
    >>> before msg #2 can finish. I've also seen once where they arrived out of
    >>> order.
    >>>
    >>>
    >>> // from the client
    >>>
    >>> [server sendMsg1];
    >>>
    >>> [server sendMsg2];
    >>>
    >>> [server sendMsg3];
    >>>
    >>>
    >>> Is there another way to call asynchronously, yet guarantee that the
    >>> messages
    >>> arrive in order? Or someway to call w/o the GUI blocking for a server
    >>> message return?
    >>
    >>
    >> You can use :
    >> - NSConnection/NSPorts (
    >>
    > http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/ar
    ticles/SocketComm.html#//apple_ref/doc/uid/TP40001479

    >> )
    >> - YAMessageQueue (10.4-):
    > http://www.2pi.dk/tech/cocoa/message_queue.html
    >> - NSOperation/NSOperationQueue (10.5+) :
    >> - [NSObject performSelector:onThread]/[NSObject
    >> performSelectorInMainThread:] (10.5+);
    >>
    >>
    >> :: marcelo.alves
    >
  • On Jan 4, 2008, at 7:06 PM, William Zumwalt wrote:

    > #2) I make 3 calls to my server thread in sequence, so I marked all
    > 3 as
    > (oneway void). After doing this I was able to click on a button in
    > my GUI
    > while the thread was running, so I think the GUI was blocking w/ the
    > default
    > (inout void) ... at least I think that's the default.
    >
    >
    > However my problem now is that with all three marked as (oneway void)
    > (sending async msgs), message #2 requires a few seconds to complete
    > while
    > message #3 depends on message #2 before it can start, yet msg #3 is
    > done
    > before msg #2 can finish. I've also seen once where they arrived out
    > of
    > order.
    >
    >
    > // from the client
    >
    > [server sendMsg1];
    >
    > [server sendMsg2];
    >
    > [server sendMsg3];
    >
    >
    > Is there another way to call asynchronously, yet guarantee that the
    > messages
    > arrive in order? Or someway to call w/o the GUI blocking for a server
    > message return?

    See here:
    http://developer.apple.com/documentation/Cocoa/Conceptual/DistrObjects/Task
    s/configuring.html


    In particular, the paragraph that discusses
    setIndependentConversationQueueing:.

    -Ken
  • William Zumwalt <mailto:<wizumwalt...> wrote (Friday,
    January 4, 2008 6:06 PM -0600):

    > I've been trying to chase down a problem with my thread for sometime
    > and I think
    > I've found the problem with why I can't click on my interface even though I
    > have a thread processing my data in the background ... so I have a few
    > questions about protocol modifiers which I'm looking at as the culprit.

    William,

    You're talking about threads, but the issue is really
    Distributed Objects. While DO can send messages between threads,
    it's principle strength is its ability to communicate between
    processes and systems. Unless you *need* to communicate between
    processes, you have numerous -- and far more efficient --
    alternatives beyond DO to choose from. In your case, queuing
    messages or using some other kind of inter-thread FIFO would
    probably serve your needs.

    Distributed Objects works through the run loop. When you send a
    message to a distant object, the object and the method
    invocation is encoded and piped to a port on the run loop that
    created the object. The run loop dispatches the message and send
    the results back to the run loop of the process/thread that sent
    the message.

    As you've discovered, unless you use the (oneway void) modifier,
    the sender blocks until the reply message is placed on its run loop.

    As for the out-of-order messages, I don't think there are any
    delivery order guarantees in DO. It's impractical that there
    would be any, since DO is designed to work over asynchronous
    communication links.

    My long-winded point is this: Your "server" is really a worker
    thread. It performs work in a separate thread within the same
    process and needs to deliver that work to your main thread when
    done. Distributed Objects really isn't the best fit for this pattern.

    As others have suggested, I suspect that something like
    YAMessageQueue is a much better solution for your application.
    It's thread friendly, doesn't have any object encoding/decoding
    overhead, doesn't require any special declarations, and it won't
    gum up your run loops.

    --
    James Bucanek
  • > You're talking about threads, but the issue is really
    > Distributed Objects. While DO can send messages between threads,
    > it's principle strength is its ability to communicate between
    > processes and systems. Unless you *need* to communicate between
    > processes, you have numerous -- and far more efficient --
    > alternatives beyond DO to choose from. In your case, queuing
    > messages or using some other kind of inter-thread FIFO would
    > probably serve your needs.
    >

    But I think that's the reason I chose to use DO, because I am communicating
    between processes by having my client send several hundred or more objects
    of data, and then send commands for the server to operate on that data.

    >
    > Distributed Objects works through the run loop. When you send a
    > message to a distant object, the object and the method
    > invocation is encoded and piped to a port on the run loop that
    > created the object. The run loop dispatches the message and send
    > the results back to the run loop of the process/thread that sent
    > the message.
    >
    > As you've discovered, unless you use the (oneway void) modifier,
    > the sender blocks until the reply message is placed on its run loop.
    >

    So I feel that I'm still using the right method to communicate with, but you
    have raised something important that I hadn't seen before. I'm showing my
    servers run loop below, but what I'm wondering about is that the class that
    subclasses this main server class where I implement my commands ... it has
    it's own main loop (which I try to show in the 'run' method below).

    Here is how I create my server process (serverObject), and once my server is
    up and running, it is then able to receive a command such as 'run', 'pause',
    etc...

    + (void) _connectWithPorts:(NSArray *) portArray
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        NSConnection *controllerConnection = [NSConnection
            connectionWithReceivePort:[portArray objectAtIndex:0]
            sendPort:[portArray objectAtIndex:1]];

        int serverTag = [[portArray objectAtIndex:2] intValue];

        /*
        * Now we create the server instance that will actually do the data
        * processing. Actual data processing behavior will be in the subclass.
        */
        NetworkServer *serverObject = [[self alloc]
            initForParent:(id) [controllerConnection rootProxy]
    withTag:serverTag];
        [serverObject setConnection:controllerConnection];

        [controllerConnection setRootObject:serverObject];

        @try {
            [[controllerConnection rootProxy] setServer:serverObject
                tag:serverTag];
        }
        @catch (NSException *exception) {
            NSLog(@"NetworkServer:_connectWithPorts caught %@: %@",
                [exception name], [exception  reason]);
        }

        [[controllerConnection rootProxy]
            performSelectorOnMainThread:@selector(handleServerSetupComplete)
            withObject:nil waitUntilDone:NO];

        do {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                beforeDate:[NSDate distantFuture]];
        } while ([serverObject isRunning]);

        [[controllerConnection receivePort] invalidate];
        [[controllerConnection sendPort] invalidate];
        [controllerConnection release];

        [serverObject release];
        [pool release];
    }

    Two example commands that this server is able to receive.

    - (void) run
    {
        [self _run];

        return;
    }

    - (void) pause
    {
        [self _pause];

        return;
    }

    The data processing implementation methods are in a subclass of the server
    class above and has it's own main loop to process data. Could this be the
    problem because you said DO works through the run loop, and I don't think
    I'm giving it a chance to return back into the run loop because the server
    process is hung up inside this loop processing data.

    - (void)_run
    {
        ...

        while (processingData) {
          ...
        }
    }
  • I wanted to make a separate reply to the points below so as not to be too
    long winded in my previous post. I didn't understand the pattern point
    below.

    My long-winded point is this: Your "server" is really a worker
    > thread. It performs work in a separate thread within the same
    > process and needs to deliver that work to your main thread when
    > done. Distributed Objects really isn't the best fit for this pattern.
    >

    What pattern is it you think I'm doing? I'm communicating between processes,
    so ... after seeing my latest previous post which might clarify things, do
    you still think I'm using the wrong communication method?

    If it helps any, I pulled this almost directly out of the book "Cocoa
    Programming" from chapt. 24 on Subprocesses and Threads which I thought fit
    exactly what I was trying to do (downloadable too).
    http://www.cocoaprogramming.net/
  • William Zumwalt <mailto:<wizumwalt...> wrote (Saturday,
    January 5, 2008 2:44 PM -0600):
    >
    > What pattern is it you think I'm doing?

    It sounds a lot like a "worker" pattern where a thread operates
    on a queue of pending jobs and posts the results when its done.
    In this model, the worker is usually designed so that the "jobs"
    are executed in a specific order.

    A client/server using RPC is usually intended to provide
    synchronous responses to queries from external processes. While
    a worker could be implemented in a server, the server model
    itself doesn't provide exactly what you're asking for.

    > I'm communicating between processes,
    > so ... after seeing my latest previous post which might clarify things, do
    > you still think I'm using the wrong communication method?

    It's hard to say. We need to clear up the point about where
    (same process or different process) your "server" thread is running.

    --
    James Bucanek
  • William Zumwalt <mailto:<wizumwalt...> wrote (Saturday,
    January 5, 2008 2:35 PM -0600):

    >> You're talking about threads, but the issue is really
    >> Distributed Objects. While DO can send messages between threads,
    >> it's principle strength is its ability to communicate between
    >> processes and systems. Unless you *need* to communicate between
    >> processes, you have numerous -- and far more efficient --
    >> alternatives beyond DO to choose from. In your case, queuing
    >> messages or using some other kind of inter-thread FIFO would
    >> probably serve your needs.
    >>
    >
    > But I think that's the reason I chose to use DO, because I am communicating
    > between processes by having my client send several hundred or more objects
    > of data, and then send commands for the server to operate on that data.

    The $64,0000 question is this: Is your server a separate process
    or just a thread in your application's process.

    If your server is really running as it's own process, then DO is
    the way to go. If your server is just a new thread started
    within your application, then DO is probably more trouble than
    it's worth (for this particular situation).

    Note that the programming snippets that you included don't
    answer the question because it doesn't show how the
    _connectWithPorts: method gets started. Is this initialization
    code in a separate executable? Then it's probably running as a
    separate process. However, if you start _connectWithPorts: with
    +[NSThread detachNewThreadSelector:...] then it's just another
    tread within your application's process. It's a very important
    distinction to make.

    > The data processing implementation methods are in a subclass of the server
    > class above and has it's own main loop to process data. Could this be the
    > problem because you said DO works through the run loop, and I don't think
    > I'm giving it a chance to return back into the run loop because the server
    > process is hung up inside this loop processing data.
    >
    > - (void)_run
    > {
    > ...
    >
    > while (processingData) {
    > ...
    > }
    > }
    >

    That's exactly how DO works. If you need to get back to your run
    loop to dispatch the next message in the queue, then you need to
    return from _run sooner. For example, forking a new thread to do
    the work then returning from _run immediately. But this just
    pushes your worker threads one level deeper in the architecture;
    it's really not solving any of your fundamental problems.

    --
    James Bucanek
  • > It's hard to say. We need to clear up the point about where
    > (same process or different process) your "server" thread is running.
    >

    OK, to clarify, my user kicks off a job which causes a thread to start like
    this ...

    + (NSConnection *) startNetworkThreadWithTag:(int) tag
        forController:(id <ClientMethods>) controller
    {
        ...
        [NSThread detachNewThreadSelector:@selector(_connectWithPorts:)
            toTarget:self withObject:portArray];

    Maybe this will help explain my intentions ... once the thread is started
    doesn't mean I'm processing data yet, this just sets up the server process
    and passes all my potentially thousands of encoded objects to the server
    which is not it's own app process, rather, just another thread from within
    the application process. Then the user can click on media like buttons to
    run, pause, save, and stop on the data processing and terminate the thread
    after saving the results.

    It's a scientific application and it's likely the user will repeat this
    process many times testing new configurations so I expect the many different
    server object types, all w/ different algorithms that are subclassed, to get
    run in a single session. But the server object itself isn't expected to stay
    up for the life of the application, it's just a data processing thread that
    may last for a few minutes + depending on the amount of data, only to be
    followed by another user configuration of data and another data processing
    test.

    What initially influenced my decision was that I had a lot of data patterns
    that needed to be communicated to the server thread and rather than pass
    pointers to the data, I passed the objects themselves so that the server
    process would have it's own copy of the data to operate on and not have to
    worry about the user changing it while it's being operated on.

    Ugh, how disappointing all this work is turning out to be. I thought I had
    something neat that was really going to work.
  • On Jan 5, 2008, at 8:35 PM, William Zumwalt wrote:

    >> It's hard to say. We need to clear up the point about where
    >> (same process or different process) your "server" thread is running.
    >>
    >
    >
    > OK, to clarify, my user kicks off a job which causes a thread to
    > start like
    > this ...
    >
    > + (NSConnection *) startNetworkThreadWithTag:(int) tag
    > forController:(id <ClientMethods>) controller
    > {
    > ...
    > [NSThread detachNewThreadSelector:@selector(_connectWithPorts:)
    > toTarget:self withObject:portArray];
    >

    Just as a stylistic matter that should be followed to avoid having
    strange and unexpected problems, don't use the leading underscore.
    From <http://developer.apple.com/documentation/Cocoa/Conceptual/CodingGuidelines/
    Articles/NamingMethods.html
    >:

    > Names of most private methods in the Cocoa frameworks have an
    > underscore prefix (for example,_fooData ) to mark them as private.
    > From this fact follow two recommendations.
    >
    > •
    > Don’t use the underscore character as a prefix for your private
    > methods. Apple reserves this convention.
    >
    >
    >

    Glenn Andreas                      <gandreas...>
      <http://www.gandreas.com/> wicked fun!
    quadrium | flame : flame fractals & strange attractors : build,
    mutate, evolve, animate

    Glenn Andreas                      <gandreas...>
      <http://www.gandreas.com/> wicked fun!
    quadrium | prime : build, mutate, evolve, animate : the next
    generation of fractal art
  • > Just as a stylistic matter that should be followed to avoid having
    > strange and unexpected problems, don't use the leading underscore.
    > From <
    > http://developer.apple.com/documentation/Cocoa/Conceptual/CodingGuidelines/
    Articles/NamingMethods.html

    >> :
    >

    Thanks, I'm now surprised that the book I'm learning from (Cocoa
    Programming) uses this.
  • William Zumwalt <mailto:<wizumwalt...> wrote (Saturday,
    January 5, 2008 7:35 PM -0600):
    > Maybe this will help explain my intentions ... once the thread is started
    > doesn't mean I'm processing data yet, this just sets up the server process
    > and passes all my potentially thousands of encoded objects to the server
    > which is not it's own app process, rather, just another thread from within
    > the application process. Then the user can click on media like buttons to
    > run, pause, save, and stop on the data processing and terminate the thread
    > after saving the results.

    That at least settles the same-process question.

    > It's a scientific application and it's likely the user will repeat this
    > process many times testing new configurations so I expect the many different
    > server object types, all w/ different algorithms that are subclassed, to get
    > run in a single session. But the server object itself isn't expected to stay
    > up for the life of the application, it's just a data processing thread that
    > may last for a few minutes + depending on the amount of data, only to be
    > followed by another user configuration of data and another data processing
    > test.
    >
    > What initially influenced my decision was that I had a lot of data patterns
    > that needed to be communicated to the server thread and rather than pass
    > pointers to the data, I passed the objects themselves so that the server
    > process would have it's own copy of the data to operate on and not have to
    > worry about the user changing it while it's being operated on.

    Sadly, I have bad news. You have two needs, neither of which is
    going to be solved using distributed objects. (Well, technically
    one could but it's not a good use of DO.)

    What you need is:

    (a) A worker thread that has an object to do the work.
    (b) A message system by which you send jobs to the worker thread
    to be performed asynchronously. The jobs need to be performed in
    the order they were queued.
    (c) The worker works on a copy of the original object.

    Distributed Objects is an IPC/RPC mechanism. It's purpose is to
    allow you to communicate with a remote object (one that might
    exist in another process or even another machine) as though it
    was a local object. While it uses run loop queues to perform its
    communications, it's not designed to manage queues of
    asynchronous jobs/messages. In fact, DO primary purpose is to
    provide a synchronous method calling. And while it will make
    copies of objects, it normally does not. The object that the
    server uses is (conceptually) the same object that the client
    sent it. Any changes made to the object by the server will
    affect the original object.

    So what you're trying to do is turn the side-effects of
    distributed objects into a worker thread management system. You
    might make it work, but you're fighting an uphill battle.

    My suggestion would be to take a step back and look at something
    like YAMessageQueue. The changes in your code should be minimal.
    Instead of creating a server and starting a thread which starts
    a run loop, your code would

    (a) Start a thread, passing it a copy of the object that will do
    the work
    (b) Send it messages to perform using YAMessageQueue (or some
    similar mechanism).
    (c) When the message finishes executing, it can communicate the
    results back to the main thread via another queue or simply with
    [NSObject peformSelectorOnMainThread:...]
    (d) Implement the NSCopying protocol on the objects you need to
    copy. (Sending an object to a server using DO doesn't make a
    copy of it; it only creates a proxy objects that eventually
    invokes changes on the original.)

    This solution will be vastly more efficient, and probably easier
    to write and maintain. More importantly, you'll have real
    control over message execution order and scheduling.

    --
    James Bucanek
  • Thanks James, this was all very helpful.

    This solution will be vastly more efficient, and probably easier
    > to write and maintain. More importantly, you'll have real
    > control over message execution order and scheduling.
    >
  • Are you targeting Leopard?

    If so, look at NSOperation and NSOperationQueue.

    See this link for an example of use in a scientific environment:

    Cocoa for Scientists (Part XXI): Multi-Threading Your App with
    NSOperation and NSOperationQueue

    http://www.macresearch.org/node/4567

    On Jan 6, 2008, at 12:28 AM, William Zumwalt wrote:

    > Thanks James, this was all very helpful.
    >
    >
    > This solution will be vastly more efficient, and probably easier
    >> to write and maintain. More importantly, you'll have real
    >> control over message execution order and scheduling.
    >>


    --
    Blog:  http://www.bagelturf.com/  Photos: http://
    bagelturf.smugmug.com/  Buy my book: http://www.bagelturf.com/
    products/getyourheadaroundaperture/
previous month january 2008 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today