Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
TransferServer.m
/* |
File: TransferServer.m |
Contains: Sample server class, talked to through Distributed Objects. |
Written by: Quinn "The Eskimo!". |
Modified by Timothy Carroll |
Created: Tue 10-Jun-1997 |
Copyright: (c)1997 by Apple Computer, Inc., all rights reserved. |
Change History (most recent first): |
You may incorporate this sample code into your applications without |
restriction, though the sample code has been provided "AS IS" and the |
responsibility for its operation is 100% yours. However, what you are |
not permitted to do is to redistribute the source as "DSC Sample Code" |
after having made changes. If you're going to re-distribute the source, |
we require that you make it clear in the source that the code was |
descended from Apple Sample Code, but that you've made changes. |
*/ |
#import "TransferServer.h" |
#import "Controller.h" |
// IMPORTANT: See the documentation ("ReadMe.rtf" under Supporting Files) for |
// big picture information about this project. |
static long transferCount; |
// This variable holds the count of the number of transfers |
// by any object of this class. We use this to generate the |
// transfer ID for a transfer, which is helpful in debugging |
// the output of the transfers, matching up starts with finishes |
// and so on. |
static NSLock *transferCountLock; |
// This is a lock for the above variable because it's used by |
// multiple different threads. |
static long threadCount; |
static NSLock *threadCountLock; |
static NSConnection *theConnection; |
@implementation TransferServer |
+ (void)initialize |
// This method is called before any other methods in our class |
// are called. We use it to set up the transferCount variable |
// and its lock. |
{ |
static BOOL tooLate = NO; |
// initialize should only be called once. If it's called |
// a second time, something weird is happening, and we want |
// to know about it. |
NSAssert( ! tooLate, @"Hmm, duplicate initialize messages"); |
transferCount = 0; |
transferCountLock = [[NSLock alloc] init]; |
NSAssert( transferCountLock != nil, @"Could not create transferCountLock"); |
threadCount = 0; |
threadCountLock = [[NSLock alloc] init]; |
NSAssert( threadCountLock != nil, @"Could not create threadCountLock"); |
tooLate = YES; |
} |
+ (long)newTransferID |
// This method increments the transferCount global variable |
// and returns it as the new transfer ID. Transfer operations |
// call this method to get a unique ID with which to stamp |
// their transfers, which helps in debugging the concurrent |
// operations in progress. Note that we have to lock |
// transferCount before modifying it, let another thread |
// execute while we're halfway through modifying it. |
{ |
long result; |
[transferCountLock lock]; |
transferCount += 1; |
result = transferCount; |
[transferCountLock unlock]; |
return (result); |
} |
+ (void)connectWithPorts:(NSArray *)portArray |
// See comments in implementation part. |
{ |
NSAutoreleasePool *pool; |
NSConnection *connectionToController; |
TransferServer *serverObject; |
// First we must create an autorelease pool. Methods that we invoke |
// are going to expect to be able to do [object autorelease], but this |
// doesn't work unless we explicitly create an autorelease pool because |
// we're running in a new thread, and threads don't start off with a |
// default autorelease pool. |
pool = [[NSAutoreleasePool alloc] init]; |
// Now we connect back to the main thread using the ports given in our |
// portArray argument. Note the subtle difference in that we use |
// connectWithReceivePort here, whereas Controller's init method uses |
// initWithReceivePort. |
connectionToController = [NSConnection connectionWithReceivePort:[portArray objectAtIndex:0] |
sendPort:[portArray objectAtIndex:1]]; |
// Now create a server object. In this example, we only have one server |
// object to handle all requests. |
serverObject = [[self alloc] init]; |
// Now get the proxy of the root object at the other end of the connection |
// (which was set to be the controller object in Controller's init method) |
// and send it the setServer message so that it knows about our server object. |
// Note that there is nothing magic about the method name "setServer"; it's |
// merely the name I decided to use when designing these two objects. |
[connectionToController setRootObject:serverObject]; |
// We now release our server object, so the controller has the only reference |
// to it. Well, actually, the NSConnection also has a reference to it, |
// which is what keeps the object around until the main thread picks it up. |
[serverObject release]; |
theConnection = connectionToController; |
// Now we enter our run loop. The run loop waits looking for events and |
// executes them. In the case of a non-application thread, the source |
// of events is the NSConnections installed in the loop. In our case, this |
// in the NSConnection we created earlier in this routine. When a DO |
// message arrives on our receive port, the run loop unpackages the message |
// and executes the corresponding Objective-C method. |
[[NSRunLoop currentRunLoop] run]; |
// Clean up. |
[pool release]; |
[NSThread exit]; |
return; |
} |
- (id)init |
// See comments in interface part. |
{ |
self = [super init]; |
if (self != nil) { |
[threadCountLock lock]; |
threadCount += 1; |
threadID = threadCount; |
[threadCountLock unlock]; |
} |
return (self); |
} |
- (oneway void)slowTransfer:(Controller *)controller |
// See comments in interface part. |
{ |
long i; |
long transferID; |
transferID = [TransferServer newTransferID]; |
[controller outputString:[NSString stringWithFormat:@"Thread = %02ld, Connection's retain count is %02ld\n", threadID , [theConnection retainCount]]]; |
[controller outputString:[NSString stringWithFormat:@"Thread = %02ld, Connection's retain count is %02ld\n", threadID , [theConnection retainCount]]]; |
[controller outputString:[NSString stringWithFormat:@" Starting slowTransfer Thread=%02ld, ID=%02ld\n", |
threadID, transferID] ]; |
for (i = 0; i < 3; i++) { |
// Sleep for 1 second and then output a progress string to the controller. |
// You could substitute any other synchronous activity here, such as an |
// extended computation, or blocking I/O (file system or network). |
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; |
[controller outputString: |
[NSString stringWithFormat:@" Doing slowTransfer Thread=%02ld, ID=%02ld, Step=%ld\n", |
threadID, transferID , i] ]; |
} |
[controller outputString:[NSString stringWithFormat:@" Finished slowTransfer Thread=%02ld, ID=%02ld\n", |
threadID, transferID]]; |
[controller outputString:[NSString stringWithFormat:@"Thread = %02ld, Connection's retain count is %02ld\n", threadID , [theConnection retainCount]]]; |
[controller serverFinished:self]; |
} |
- (oneway void)slowerTransfer:(Controller *)controller |
// See comments in interface part. |
{ |
long i; |
long transferID; |
transferID = [TransferServer newTransferID]; |
[controller outputString:[NSString stringWithFormat:@" Starting slowerTransfer Thread=%02ld, ID=%02ld\n", |
threadID, transferID]]; |
for (i = 0; i < 10; i++) { |
// See comment in slowTransfer:. |
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; |
[controller outputString: |
[NSString stringWithFormat:@" Doing slowerTransfer Thread=%02ld, ID=%02ld, Step=%ld\n", |
threadID, transferID , i] ]; |
} |
[controller outputString:[NSString stringWithFormat:@" Finished slowerTransfer Thread=%02ld, ID=%02ld\n", |
threadID, transferID]]; |
[controller outputString:[NSString stringWithFormat:@"Thread = %02ld, Connection's retain count is %02ld\n", threadID , [theConnection retainCount]]]; |
[controller serverFinished:self]; |
} |
@end |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14