[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
---------------------------------------
- Inter-thread communication with NSPort,
Tima <=