discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Inter-thread communication with NSPort


From: Tima
Subject: Inter-thread communication with NSPort
Date: Fri, 02 Feb 2007 23:32:32 -0800
User-agent: GNUMail (Version 1.2.0)

Hi,

I'm trying to make a client-server application in GNUstep.
Right now it seems that the best way to do the client is to
make it a two-threaded application, with a main thread processing
GUI events and a "worker" thread waiting and reading messages
from socket-related NSInputStream.

I want the worker thread to notify the main one when the message is ready.
After reading Apple documentation for some time I got an impression
that I need to send message to main thread's NSPort, it will be delivered
via -handlePortMessage: method of the port's delegate.

First of all, is it really the intended way to do communication
between threads?

Secondly, I tried to do this myself, but my message does not seem
to propagate from worker thread into the main one: the
-handlePortMessage: wasn't called.

Could you tell me what's wrong in the following program?

I apologize for rather big size of it, but that's the minimal size of
the test case I could get.

Thank you,
Tima

---------------------------- begin thread.m ---------------------------------
#include <AppKit/AppKit.h>

@interface WorkerThread : NSObject
{
    NSPort * _remotePort;
}

+ (void) startThreadWithObject: (id) object;

- (void) confirmLaunchToPort: (NSPort *) remotePort;
- (void) handlePortMessage:(NSPortMessage *) portMessage;

@end


@implementation WorkerThread

- (id ) init
{
    _remotePort = NULL;
    return [super init];
}

- (void) dealloc
{
    [_remotePort release];
    [super dealloc];
}

+ (void) startThreadWithObject: (id) inputObject
{
    NSAutoreleasePool * pool = [NSAutoreleasePool new];

    NSPort * remotePort = [[NSMessagePortNameServer sharedInstance]
                              portForName: @"MainThread"];

    if ( remotePort )
    {
        WorkerThread * worker = [self new];

        [worker confirmLaunchToPort: remotePort];

        //[remotePort release];

        NSLog( @"WorkerThread: starting message loop" );

        [[NSRunLoop currentRunLoop] run];

        [worker release];
        [pool release];
    }

    NSLog( @"WorkerThread: exiting thread" );
}

- (void) confirmLaunchToPort: (NSPort *) remotePort
{
    // Save remote port
    _remotePort = remotePort;
    [_remotePort retain];

    // Configure local port
    NSPort * localPort = [[[NSMessagePort alloc] init] retain];

    [[NSMessagePortNameServer sharedInstance] registerPort:localPort
forName: @"WorkerThread"];
    [localPort setDelegate: self];

    [[NSRunLoop currentRunLoop] addPort: localPort
                                forMode: NSDefaultRunLoopMode];

    // Create confirmation message

    NSArray * comps =
[NSArray arrayWithObject: [NSData dataWithBytes: "0" length: 1 ]];

NSLog( @"WorkerThread: -confirmLaunch: localPort=0x%x, remotePort=0x%x",
           localPort, _remotePort );

    NSPortMessage * message =
        [[NSPortMessage alloc] initWithSendPort: _remotePort
                               receivePort: localPort
                               components: comps];

    if ( message )
    {
        BOOL res = [message sendBeforeDate:[NSDate distantFuture]];
NSLog( @"WorkerThread: sendBeforeDate: %s", res ? "ok" : "FAIL" );
    }
}

- (void) handlePortMessage:(NSPortMessage *) portMessage
{
    unsigned int messageID = [portMessage msgid];
    NSLog( @"WorkerThread: port message, ID = %d", messageID );
}

@end /* WorkerThread */

@interface AppController : NSObject

- (void) applicationWillFinishLaunching: (NSNotification *)not;
- (void) createMenu;
- (void) startWorkerThread;
- (void) handlePortMessage:(NSPortMessage *) portMessage;

@end

@implementation AppController

- (void) startWorkerThread
{
    NSLog( @"AppController: Starting thread" );

    NSPort * localPort = [[[NSMessagePort alloc] init] retain];
    NSLog( @"AppController: localPort=0x%x", localPort );
    if ( localPort )
    {
        // Register local NSMessagePort
[[NSMessagePortNameServer sharedInstance] registerPort:localPort forName: @"MainThread"];

        // Set delegate
        [localPort setDelegate: self];

        // Add port to run loop
        [[NSRunLoop currentRunLoop] addPort: localPort
                                    forMode: NSDefaultRunLoopMode];

        // Launch the thread
[NSThread detachNewThreadSelector:@selector(startThreadWithObject:)
                  toTarget:[WorkerThread class] withObject: 0];
    }
}

// Handle responses from the worker thread.

- (void) createMenu
{
    NSMenu * menu = [[NSMenu new] autorelease];
    [NSApp setMainMenu: menu];

    [menu addItemWithTitle:@"Quit"
          action:@selector(terminate:)
          keyEquivalent:@"q"];
}

- (void) applicationWillFinishLaunching: (NSNotification *)not
{
    [self createMenu];
    [self startWorkerThread];
}

- (void) handlePortMessage:(NSPortMessage *) portMessage
{
    unsigned int messageID = [portMessage msgid];
    NSLog( @"AppController: port message, ID = %d", messageID );
}

@end /* AppController */

int main (int argc, const char **argv)
{
    [NSApplication sharedApplication];
    [NSApp setDelegate: [AppController new]];

    return NSApplicationMain (argc, argv);
}
----------------------- end thread.m ---------------------------------------





reply via email to

[Prev in Thread] Current Thread [Next in Thread]