discuss-gnustep
[Top][All Lists]
Advanced

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

Re: How to terminate another thread?


From: Stefan Urbanek
Subject: Re: How to terminate another thread?
Date: Thu, 25 Jul 2002 12:23:38 +0200

Hi David,

David Ayers wrote:
> 
> Hello Stefan,
> 
> > Well, I need it for several objects of different classes and they
> > may not have
> > common ancestor, only NSObject. I want the objects to be something like
> > 'Actors' - handling asynchronous (oneway) messages. To handle
> > oneway messages
> > withot creating my own mechanisms I am using  threads. In most operating
> > systems, including linux, threads are expensive, but is there any other
> > option?
> 
> Well have you though about using NSRunLoop's
> performSelector:target:argument:order:modes: instead of using a thread for
> every object? I believe it would be the least tedious route, if you don't
> need the messages to be executed immediatly and simultaneously. But if not I
> would advise you to create a robust DO-Object to handle the messaging
> between threads rather than relying on generic-DO-Proxy-Mechanism
> implemented by NSObject. To many things can happen.
> 

I have changed my point of view and have created something like 'threads with
object' and I recycle the threads. If you are interested, sources are
attached.

    Thread *thread;
    id      proxy;

    thread = [Thread detachedThread];
    proxy = [thread setThreadObject:anObject];

    ... /* use the proxy */
    [proxy run];
    ...

    /* recycle the thread */
    proxy = [thread setThreadObject:anotherObject];


The reason I am not using NSRunLoop's performSelector: is that in some cases I
want to observe what is happening in another thread. 

I am already using one DO object that needs several thread-objects. Splitting
it into more DO objects would be really expensive. Personaly I hate those
operating-system limits and I can't wait for some object-oriented
environment/operating system without 'processes' and with very cheap 'threads'
for asynchronous messages (along with other things, like single address
space,  persistent memory and automatic grabage collection, but that is
another story).

> >
> > I thing, that NSDictionary is thread-safe, isn't it? I might be
> > wrong. Bu this
> 
> Well Foundation Kit from Apple is suposed to be thread safe, but looking
> into NS(GS)Dictionary's setObject:forKey: of GNUstep, I couldn't find an
> locking going on. So I wouldn't rely on it. But ask on the list.
> 

Ok.

> > > Well I think all you have to do is use a different way of
> > running the runloop in _establishThreadConnectionUsingParameters:
> > >
> > > use runUntilDate: providing a maximum timeout (at worst [NSDate
> > distantFuture]) and this should return once all messages are
> > processed and the thread shoud continue (and exit) normally. You
> > might need some additional mechanism to keep it running until the
> > first message has arrived, but I'm not sure on that.
> > >
> >
> > Problem is, that there is no maximum timeout. One of the possible
> > ways may be
> > running the runloop with runUntilDate:some_near_furure in a loop
> > and checking
> > womehow, if it has to be terminated.
> 
> Check the docs on runUntilDate:, it doesn't keep running if theres nothing
> left to do. Yet it will also stop at "date" even if there is something to
> do. So therefor you want to use distantFuture.
> 

Well, I tested it, and NSRunLoop seems to be running for time specified even
there is nothing to do. At least, if I use [currentRunloop
runUntilDate:five_seconds_from_now] it will pause the program for five
seconds. I am not sure, if this behaviour is ok. For exampe,in another place I
use this for waiting for NSTask to be launched, but again, I am not sure, if
it is right.


> > Ok, I have modified the code like this:
> >
> > in _establishThreadConnectionUsingParameters I have changed:
> >
> > ...
> >     threadDict = [[NSThread currentThread] threadDictionary];
> >     [threadDict setObject:self forKey:@"ThreadOwner"];
> >
> >     NSDebugLog(@"Connection established");
> >
> >     while( ![[threadDict objectForKey:@"ThreadTerminationRequest"]
> > isEqual:@"YES"] )
> >     {
> >         [[NSRunLoop currentRunLoop] runUntilDate:
> >                             [NSDate dateWithTimeIntervalSinceNow: 2]];
> >     }
> >
> >     [threadDict removeObjectForKey:@"ThreadOwner"];
> >
> >     NSLog(@"Thread terminated");
> > ...
> >
> > and added:
> >
> > - (void)terminateProxyThread
> > {
> >     NSThread     *thread = [NSThread currentThread];
> >     NSDictionary *dict = [thread threadDictionary];
> >     if([dict objectForKey:@"ThreadOwner"] == self)
> >     {
> >         NSLog(@"Thread termination request");
> >         [dict setObject:@"YES" forKey:@"ThreadTerminationRequest"];
> >     }
> >     else
> >     {
> >         NSLog(@"Could not terminate proxy thread, "
> >               @"because this object is not an owner");
> >     }
> > }
> >
> > it seems to work, but I am not sure if it is the right way.
> 
> Well It seems OK, except for the date. If there are still messages waiting
> to be executed, the runloop might end before hand.
> 

I think, that my code has to be redesingned a bit to not to use so many
threads and
try to perform those quick messages using runloops or something.

I appreciate your comments,

Stefan
/*
    Thread
    
    Written by: Stefan Urbanek
    Date: 2002 Jul 24
 */

#import <Foundation/NSObject.h>

@class NSConnection;
@class NSDistantObject;
@class NSLock;

@interface Thread:NSObject
{
    NSConnection    *localConnection;
    NSConnection    *distantConnection;

    NSDistantObject *distantSelf;

    id               object;
    NSDistantObject *distantObject;
    NSDistantObject *proxy;
    
    NSLock          *lock;
}
+ detachedThread;
- (NSDistantObject *)setThreadObject:(id)anObject;
- (id)threadObject;
- (NSDistantObject *)threadObjectProxy;
@end

/*
    Thread
    
    Written by: Stefan Urbanek
    Date: 2002 Jul 24
 */


#import "Thread.h"

#import "Externs.h"

#import <Foundation/NSConnection.h>
#import <Foundation/NSDebug.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSDistantObject.h>
#import <Foundation/NSException.h>
#import <Foundation/NSLock.h>
#import <Foundation/NSPort.h>
#import <Foundation/NSRunLoop.h>
#import <Foundation/NSString.h>
#import <Foundation/NSThread.h>

@interface Thread(Private)
- (void)_establishConnection;
- (void)_setDistantSelf:(NSDistantObject *)anObject;
- (void)_setObjectProxy:(NSDistantObject *)anObject;
@end

@implementation Thread:NSObject
+ detachedThread
{
    Thread *thread;
    
    thread = [[self alloc] init];
    
    [thread detach];
    
    return AUTORELEASE(thread);
}
- init
{
    self = [super init];
    
    lock = [[NSLock alloc] init];
    
    return self;
}
- (void)dealloc
{
    RELEASE(proxy);
    RELEASE(object);
    RELEASE(lock);
    [super dealloc];
}

- (NSDistantObject *)setThreadObject:(id)anObject
{
    NSDistantObject *tempProxy;
    
    [lock lock];
    
    if(!distantSelf)
    {
        [NSException raise:InternalInconsistencyException
                    format:@"Unable to set thread object. "
                           @"Thread is not detached."];

        [lock unlock];
        
        return nil;
    }

    proxy = nil;
    ASSIGN(object,anObject);
    
    [distantSelf _setObjectProxy];
    
    NSDebugLLog(@"Thread",@"Waiting for proxy to be set");

    while( !proxy )
    {
        [[NSRunLoop currentRunLoop] runUntilDate: 
                            [NSDate dateWithTimeIntervalSinceNow: 1]];
        NSDebugLLog(@"Thread",@"... still waiting ...");
    }

    NSDebugLLog(@"Thread",@"Proxy is %@ (is proxy %i)", proxy, [proxy isProxy]);

    NSDebugLLog(@"Thread",@"local connection   %@", localConnection);
    NSDebugLLog(@"Thread",@"distant connection %@", distantConnection);

    NSDebugLLog(@"Thread",@"distant self       %@", [distantSelf 
connectionForProxy]);
    NSDebugLLog(@"Thread",@"proxy              %@", [proxy connectionForProxy]);

    tempProxy = proxy;

    [lock unlock];

    return tempProxy;
}

- (void)detach
{
    NSDictionary    *dict;
    NSPort          *port1;
    NSPort          *port2;
    
    if(distantSelf)
    {
        [NSException raise:InternalInconsistencyException
                    format:@"Thread is already detached."];
        return;
    }
    
    NSDebugLLog(@"Thread",@"Creating new thread connection");

    port1 = [NSPort port];
    port2 = [NSPort port];

    localConnection = [[NSConnection alloc] initWithReceivePort:port1
                                                  sendPort:port2];
    [localConnection setRootObject:self];

    /* Ports switched here. */
    dict = [NSDictionary dictionaryWithObjectsAndKeys:
                                port2,     @"ReceivePort",
                                port1,     @"SendPort",
                                nil,        nil];


    [NSThread 
detachNewThreadSelector:@selector(establishThreadConnectionUsingParameters:)
                             toTarget:self
                           withObject:dict];

    NSDebugLLog(@"Thread",@"Waiting for connection to be established");

    while( !distantSelf )
    {
        [[NSRunLoop currentRunLoop] runUntilDate: 
                            [NSDate dateWithTimeIntervalSinceNow: 1]];
        NSDebugLLog(@"Thread",@"... still waiting ...");
    }

    NSDebugLLog(@"Thread",@"Connection established to %@ (is proxy %i)", 
distantSelf, [distantSelf isProxy]);
}

- (void)establishThreadConnectionUsingParameters:(NSDictionary *)dict
{
    NSAutoreleasePool   *pool = [[NSAutoreleasePool alloc] init];
    
    /* executed in new second thread */

    NSDebugLLog(@"Thread",@"Establishing connection to %@", self);

    distantConnection = [NSConnection
                    connectionWithReceivePort:[dict objectForKey:@"ReceivePort"]
                                     sendPort:[dict objectForKey:@"SendPort"]];
    
    [[distantConnection rootProxy] _setDistantSelf:self];

    NSDebugLLog(@"Thread",@"Connection established");

    [[NSRunLoop currentRunLoop] run];

    NSLog(@"Thread died!");

    RELEASE(pool);

    return;
}
- (void)_setDistantSelf:(NSDistantObject *)anObject
{
    /* executed in the first thread */
    distantSelf = RETAIN(anObject);
}

- (void)_setObjectProxy
{
    /* executed in second thread */

    /*  sets 'proxy' to be proxy for anObject in first thread 
       in localConnection */
       
    [[distantConnection rootProxy] _setLocalProxy:object];
}

- (void)_setLocalProxy:(NSDistantObject *)anObject
{
    /* executed back in the first thread */
    
    proxy = RETAIN(anObject);
}

- (id)threadObject
{
    return object;
}

- (NSDistantObject *)threadObjectProxy
{
    return proxy;
}
@end


reply via email to

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