home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!overload!dillon
- From: dillon@overload.Berkeley.CA.US (Matthew Dillon)
- Newsgroups: comp.sys.next.programmer
- Subject: NS3.0 Distributed objects questions / example code
- Distribution: world
- Message-ID: <dillon.0nd9@overload.Berkeley.CA.US>
- Date: 7 Sep 92 14:25:26 PST
- Organization: Not an Organization
- Lines: 387
-
- This documentation is *AWEFUL*!! You get little one paragraph
- descriptions that tell you very little about how things are supposed to
- work. There were only 3 examples in the NeXT supplied documentation
- for distributed objects and the one I was interested in --
- multi-threading on the server side, is broken (it leaves threads lying
- around after the client exits).
-
- If anyone has any idea re: the following I would greatly appreciate an
- answer. Please post answers to the net!
-
- Goal:
-
- I have a server process which registers a named
- NXConnection. I have N client processes which wish
- to connect to this server process.
-
- I want the server to SILENTLY fork off a thread for each client
- that connects to it.
-
- Problems:
-
- Currently this does not seem possible without writing a bandaid
- called 'newThread' which the client must then call. Unfortunately,
- this bandaid not only requires the client to KNOW that the server
- is doing something wierd (it should be invisible), but also causes
- the server to call its - connection method whenever any method is
- called using the original proxy.
-
- (1) The - connection method is described in all of one paragraph
- in the NeXT documentation. It does not give you any hint
- on how the arguments are supposed to be used and how the
- returned connection is interpreted.
-
- In example program #1 below the - connection method is called
- just once for each client no matter how many operations that
- client performs on its proxy. This works as expected
-
- (2) Normally the inPort for a new connection <newConn> is the same
- as the inPort for the registration <conn>, meaning that you
- cannot fork off a thread to handle that connection because all
- the threads will try to read data from the same port. That
- is, you want a particular thread to process a particular
- connection and no other.
-
- So, in example #2 I tried to use connectToPort:withInPort: to
- setup a separate inPort for the connection then run said
- connection in a new thread. Unfortunately, this didn't work
- big time:
-
- (a) The - connection method on the server is run EACH TIME
- the client calls a method in its original proxy object (it
- didn't do this in example #1!!). This appears to be due to my
- returning something other then <conn> in the - connection
- method.
-
- (b) Further, the client's proxy does not appear to access the
- new port.
-
- (c) If the client then calls the - newThread method it
- obtains a new proxy object which DOES appear to use the
- proper connection (the one that I tried to setup and fork
- off to a separate thread). This is the bandaid, but has
- bad side effects as I described above.
-
- (3) registerForInvalidationNotification does not appear to work
- at all. It does not work with the NeXT provided examples.
- When a client exits the server is never notified and the now
- defunct thread sticks around. (example program #2)
-
- use 'ps m' to list the threads
-
- I don't want alienate NeXT but I gotta say that you guys (NeXT people)
- MUST provide more SELF CONTAINED (i.e. compilable) examples to
- demonstrate all the quirks your documentation doesn't talk about. It
- took me ALL DAY to just get as far as I did and half of what I learned
- isn't covered in any documentation anywhere. The only thing of any use
- are the few examples in Examples/ ... most of the examples embedded in
- the documentation are totally useless because they assume you
- understand the 10,000 items that had to be setup before the particular
- lines shown in the example. That's no example!
-
- Any Netter's out there who've figured this out would have my undying
- thanks if they posted the solution to the net!
-
- Thanks,
-
- -Matt
-
- ------------------------------- CUT HERE ---------------------------
-
-
- /*
- * MTHREAD1.C
- *
- * Modified from developer examples
- *
- * A simple multi-threaded example
- */
-
- #import <objc/Object.h>
- #import <remote/NXConnection.h>
- #import <remote/NXProxy.h>
- #import <mach/cthreads.h>
- #import <machkit/NXPort.h>
- #import <machkit/senderIsInvalid.h>
-
- /*
- * Our protocol
- */
-
- @protocol ServerProtocol
- - newThread;
- - (int) doWork;
- @end
-
- /*
- * Our object class which uses the protocol
- */
-
- @interface MTS : Object <ServerProtocol, NXSenderIsInvalid>
- @end
-
- /*
- * Our implementation
- */
-
- @implementation MTS
-
- /*
- * Method called when a client connects to us. connect provides us
- * with <conn>, a connection which shares topConn's input port and
- * has its own output port. The associated object is <self> (i.e. the
- * one we registered with the name sever)
- *
- * connection in this case is only called once
- */
-
- - connection: (NXConnection *)topConn didConnect:(NXConnection *)conn {
- printf("connect\n");
- [conn registerForInvalidationNotification:self];
- return(conn);
- }
-
- - senderIsInvalid: sender
- {
- puts("died!");
- }
-
- - newThread {
- puts("new thread");
- return self;
- }
-
- - (int) doWork {
- puts("do work");
- return (int) cthread_self();
- }
-
- @end
-
- /*
- * Run the program twice... the first process will be the server, the second
- * will be the client (the third will be a client, etc...)
- */
-
- main()
- {
- id hub; // proxy object (client) or server object
-
- hub = [NXConnection connectToName:"MTS example"];
-
- printf("I am %d\n", cthread_self());
-
- objc_setMultithreaded(YES);
-
- if (hub) {
- id core; // object to handle invalidation notification
- id sub;
- short i;
-
- /*
- * We are a client, <hub> is our proxy. Create <core> to handle
- * invalidation notifcation since we can't use <hub>
- */
-
- core = [[MTS alloc] init];
- [[hub connectionForProxy] registerForInvalidationNotification:core];
- [hub setProtocolForProxy:@protocol(ServerProtocol)];
-
- puts("client connect");
-
- printf("dowork is %d\n", [hub doWork]);
- printf("dowork is %d\n", [hub doWork]);
- printf("dowork is %d\n", [hub doWork]);
- printf("newThread is %08lx\n", [hub newThread]);
- printf("newThread is %08lx\n", [hub newThread]);
- printf("newThread is %08lx\n", [hub newThread]);
- } else {
- id topConn; // our server connection
-
- /*
- * Make us a server, create hub and register for invalidation
- * notification
- */
-
- hub = [MTS new];
- printf("self is %08lx\n", hub);
- topConn = [NXConnection registerRoot:hub withName:"MTS example"];
- [topConn registerForInvalidationNotification:hub];
- puts("server wait");
- [topConn setDelegate:hub]; // so hub gets connection msg
- [topConn run];
- }
- return(0);
- }
-
- ------------------------------- CUT HERE ---------------------------
-
-
- /*
- * MTHREAD2.C
- *
- * Modified from developer examples
- *
- * A simple multi-threaded example, Each new client gets a dedicated
- * thread.
- */
-
- #import <objc/Object.h>
- #import <remote/NXConnection.h>
- #import <remote/NXProxy.h>
- #import <mach/cthreads.h>
- #import <machkit/NXPort.h>
- #import <machkit/senderIsInvalid.h>
-
- /*
- * Our protocol
- */
-
- @protocol ServerProtocol
- - newThread;
- - (int) doWork;
- @end
-
- /*
- * Our object class which uses the protocol
- */
-
- @interface MTS : Object <ServerProtocol, NXSenderIsInvalid>
- @end
-
- /*
- * Our implementation
- */
-
- @implementation MTS
-
- /*
- * Connections are handled by the main thread only. Note that the
- * inPort for the proxy object obtained by the client works under
- * the 'third party server' paradigm, meaning that each accesses to
- * it is a connection. This occurs even if the 'server' is the same
- * machine as the program which posted the named port.
- *
- * topConn is the server place holder, conn is an instance connection. Note
- * that conn may/will have the same inPort as topConn. Therefore, we cannot
- * simply [conn runInNewThread] because it will compete with the main
- * thread for data.
- */
-
- - connection: (NXConnection *)topConn didConnect:(NXConnection *)conn {
- id threadConn;
- id proxy;
- id inPort = [NXPort new];
- id mts = [MTS new];
-
- puts("connect");
- proxy = [NXConnection connectToPort:[conn outPort] withInPort:inPort];
- threadConn = [proxy connectionForProxy];
- [conn free];
- [threadConn registerForInvalidationNotification:mts];
- [threadConn runInNewThread];
- [threadConn setRoot:mts];
-
- return (threadConn);
- }
-
- - senderIsInvalid: sender
- {
- printf("Sender %08lx died!\n", sender);
- write(1, "XXX\n", 4);
- }
-
- /*
- *
- */
-
- - newThread {
- printf("New Thread %08lx %d\n", self, cthread_self());
- return self;
- }
-
- - (int) doWork {
- printf("DoWork: %08lx %d\n", self, cthread_self());
- return (int) cthread_self();
- }
-
- @end
-
- /*
- * Run the program twice... the first process will be the server, the second
- * will be a client.
- */
-
- main()
- {
- id hub; // proxy object (client) or server object
-
- hub = [NXConnection connectToName:"MTS example"];
-
- printf("I am %d\n", cthread_self());
-
- objc_setMultithreaded(YES);
-
- if (hub) {
- id core; // object to handle invalidation notification
- id sub;
- short i;
-
- /*
- * We are a client, <hub> is our proxy. Create <core> to handle
- * invalidation notifcation since we can't use <hub>
- */
- core = [[MTS alloc] init];
- [[hub connectionForProxy] registerForInvalidationNotification:core];
- [hub setProtocolForProxy:@protocol(ServerProtocol)];
-
- puts("client connect");
-
- for (i = 0; i < 5; ++i) {
- sleep(1);
- printf("test-doWork %d\n", [hub doWork]);
- }
-
- sub = [hub newThread];
- for (i = 0; i < 5; ++i) {
- sleep(1);
- printf("sub %d: %d\n", i, [sub doWork]);
- }
- for (i = 0; i < 5; ++i) {
- sleep(1);
- printf("test-doWork %d\n", [hub doWork]);
- }
- sub = [hub newThread];
- for (i = 0; i < 5; ++i) {
- sleep(1);
- printf("sub %d: %d\n", i, [sub doWork]);
- }
- } else {
- id topConn; // our server connection
-
- /*
- * Make us a server, create hub and register for invalidation
- * notification
- */
-
- hub = [MTS new];
- printf("self is %08lx\n", hub);
- topConn = [NXConnection registerRoot:hub withName:"MTS example"];
- [topConn registerForInvalidationNotification:hub];
- puts("server wait");
- [topConn setDelegate:hub]; // so hub gets connection msg
- [topConn run];
- }
- return(0);
- }
-
- ------------------------------- CUT HERE ---------------------------
-
-
- --
-
- Matthew Dillon dillon@Overload.Berkeley.CA.US
- 891 Regal Rd. uunet.uu.net!overload!dillon
- Berkeley, Ca. 94708 ham: KC6LVW (no mail drop)
- USA Sandel-Avery Engineering (702)831-8000
-
-