tmh@well.UUCP (Todd M. Hoff) (10/04/89)
With the question of C++ having boolean types out of our blood, let's move on to something really challenging. QUESTION: In an event driven environment, how are events associated with the correct method within the correct object instance? How is argument parsing handled? SITUATION: For our project each process is completely event driven. A set of libraries implements event handling through a set of callback routines and work/response queues. There are a number of clients and servers using and providing various services. Applications process events from multiple sources including a user interface manager, several database managers, processes on remote machines asnchronously emitting events, and a few others. In each application are multiple objects handling these events and controlling remote objects. The problem is how to associate an event with a particular method within a particular object instance. Events arrive and they must be processed. Use which object? Which method? How is the message translated into method arguments? The situation is complicated even more by the heterogenaity of the event message formats. Some messages are basically just serialized C structures and others are CMIP messages encoded in ASN.1, needing A LOT of decoding. So there is no standard message format or standard set of arguments to pass. SOLUTION: The problem seems to stem around the inability to send a message to an object, something like: objID selector data. There's function overloading, but function overloading assumes you're in a context such that you know what method to call. In an event driven environment the former is rarely the case. I have a couple of possible solutions, but I am hoping someone has faced this problem before and has an elegant painfully-obvious-on- further-reflection solution. I don't consider endless switch statements a real solution. Thanks in advance tmh@well
nagle@well.UUCP (John Nagle) (10/04/89)
What you really need is serious concurrency support. Here's why. With a language like C++, there is the potential to have a lot of bookkeeping taken care of automatically as objects are created and then destroyed as scopes are exited. Unfortunately, in event-driven single-thread programs, you can't do this, because essentially all context associated with where control is in the program (basically, the information on the stack) is lost every time you go back to the top of the event loop. In principle, if one has cheap multitasking (called, variously, "threads", "lightweight processes", or "weak fork"), an elegant solution is for events which will require processing beyond the current event to fork off a new task to handle them, requesting that related events be forwarded to that task. The task can have lots of context, and lots of "auto" storage-class (in the C sense) objects. For example, if you have a program with lots of menus and windows, each time the user makes a menu selection that causes a window to be opened, it should result in a task being forked off to handle that window. User-generated events in that window are then sent to the task associated with that window. It should be possible for this process to be repeated recursively as necessary. Each of these little tasks looks a lot like an old-fashioned sequential program. Rather than always going back to the event loop, these tasks do something and wait for the user to respond. If the user wants to do something else, a higher level task will fork off a task to handle it. It helps if Ada-like exception handling is available. This provides a clean way to bail out with proper unwinding when necessary. The combination of multitasking, destructors, and exception processing makes cleanup almost painless. Also essential is automatic multitasking interlocks, or "monitors". The idea is that if you want to access data shared with another task, you must call an access function of a class that is declared as allowing object sharing across task boundaries. When one task has control inside a function of such a class, other tasks are blocked if they call a function of the class. This protects shared data automatically. When you think about this, it makes sense. An event loop is really a dumb sort of CPU dispatcher, after all. With a smarter dispatcher, we could have much more elegant programs. Now how do we get multithread C++? John Nagle
rcb@ccpv1.ncsu.edu (Randy Buckland) (10/04/89)
The best way I have found to handle things like callbacks on events is to create an object "action". I then have subclasses "action_method" and "action_function" which provide method and procedure callback actions. When setting up an event callback, I pass in a pointer to a proper action structure. When the event occurs, the event code calls the "do_it" method of the action object and the specific type of action handles how to perform the function. Randy Buckland rcb@ncsuvx.ncsu.edu
davidm@uunet.UU.NET (David S. Masterson) (10/06/89)
In article <13929@well.UUCP> nagle@well.UUCP (John Nagle) writes: > With a language like C++, there is the potential to have a lot of > bookkeeping taken care of automatically as objects are created and then > destroyed as scopes are exited. Unfortunately, in event-driven > single-thread programs, you can't do this, because essentially all context > associated with where control is in the program (basically, the information > on the stack) is lost every time you go back to the top of the event loop. > Isn't one possibility to not lose the context by calling the event loop instead of returning to it? This may require a little rearranging of callback routines because the new context (the sub-event loop) shouldn't handle all the normal callbacks, just those that make sense in the new context. If the event loop (or event handler) is treated like an object (with static memory areas), there should be no problem in constructing a new event loop. Right? > In principle, if one has cheap multitasking (called, variously, > "threads", "lightweight processes", or "weak fork"), an elegant solution is > for events which will require processing beyond the current event to fork > off a new task to handle them, requesting that related events be forwarded > to that task. The task can have lots of context, and lots of "auto" > storage-class (in the C sense) objects. > The question I have hear is not so much "buying" into the cheap multitasking (or even sub-event processing), but rather the manner of getting out of it when the subtask is done. Is there a return value from this other task or does the task signal its parent with a new event? Assume that the reason for invoking the other task was to get information from another "process" (user, database, whatever) and construct an object from that information that the current task can work with. What should be the method of giving this object back to the parent task? > Now how do we get multithread C++? > One naive question, though. Define "smart" dispatcher? David Masterson uunet!cimshop!davidm
prc@erbe.se (Robert Claeson) (10/06/89)
In article <13929@well.UUCP> nagle@well.UUCP (John Nagle) writes: > What you really need is serious concurrency support. Here's why. [---] > When you think about this, it makes sense. An event loop is >really a dumb sort of CPU dispatcher, after all. With a smarter dispatcher, >we could have much more elegant programs. > > Now how do we get multithread C++? Check out Concurrent C++ (from AT&T Bell Labs., I believe). -- Robert Claeson E-mail: rclaeson@erbe.se ERBE DATA AB
rfg@ics.uci.edu (Ronald Guilmette) (10/08/89)
In article <848@maxim.erbe.se> prc@erbe.se (Robert Claeson) writes: > >Check out Concurrent C++ (from AT&T Bell Labs., I believe). There have been papers published on "Concurrent C", but this is the first mention I have seen to "Concurrent C++". Can you provide a reference or something so that people who *are* actually interested in this can get more information. Thanks. // rfg
schmidt@zola.ics.uci.edu (Doug Schmidt) (10/08/89)
In article <1989Oct7.194345.1384@paris.ics.uci.edu>, rfg@ics (Ronald Guilmette) writes: >In article <848@maxim.erbe.se> prc@erbe.se (Robert Claeson) writes: >> >>Check out Concurrent C++ (from AT&T Bell Labs., I believe). > >There have been papers published on "Concurrent C", but this is the first >mention I have seen to "Concurrent C++". Can you provide a reference or >something so that people who *are* actually interested in this can get >more information. Check out the book `The Concurrent C Programming Language' by Narain Gehani and William D. Roome, published 1989 by Silcon Press, ISBN 0-929306-00-7. Chapter 5 discusses Concurrent C++ (this looks similar to an article published recently in Software Practice and Experience). The concurrency model in Concurrent C is based on the `rendezvous concept,' and people familiar with Ada's tasking model should feel comfortable with many of its constructs (see appendix C for a comparison between Ada and Concurrent C). I'd be interested in hearing whether anyone else has actually programmed in Concurrent C/C++, and also whether it is available for general use. It certainly sounds like an interesting extension to C/C++. Doug -- Master Swordsman speak of humility; | schmidt@ics.uci.edu (ARPA) Philosophers speak of truth; | office: (714) 856-4034 Saints and wisemen speak of the Tao of no doubt; The moon, sun, and sea speaks for itself. -- Hiroshi Hamada
schwartz@psuvax1.cs.psu.edu (Scott Schwartz) (10/08/89)
Doug Schmidt writes: | I'd be interested in hearing whether anyone else has actually | programmed in Concurrent C/C++, and also whether it is available for | general use. Here is one data point: CCC is used in some of the operating systems courses here at psu. People seem happier with this than with Concurrent Euclid, which we used to use. -- Scott Schwartz <schwartz@shire.cs.psu.edu> Now back to our regularly scheduled programming....
prc@erbe.se (Robert Claeson) (10/08/89)
In article <1989Oct7.194345.1384@paris.ics.uci.edu> Ronald Guilmette <rfg@ics.uci.edu> writes: >There have been papers published on "Concurrent C", but this is the first >mention I have seen to "Concurrent C++". Can you provide a reference or >something so that people who *are* actually interested in this can get >more information. Concurrent C++ comes from the same folks that makes Concurrent C. Concurrent C++ is a compiler option. There were an article on C++ in one of the recent issues of UNIX Review. Interesting stuff. -- Robert Claeson E-mail: rclaeson@erbe.se ERBE DATA AB
nagle@well.UUCP (John Nagle) (10/09/89)
In article <CIMSHOP!DAVIDM.89Oct5101459@uunet.UU.NET> cimshop!davidm@uunet.UU.NET (David S. Masterson) writes: >In article <13929@well.UUCP> nagle@well.UUCP (John Nagle) writes: >Isn't one possibility to not lose the context by calling the event loop >instead of returning to it? This may require a little rearranging of callback >routines because the new context (the sub-event loop) shouldn't handle all the >normal callbacks, just those that make sense in the new context. If the event >loop (or event handler) is treated like an object (with static memory areas), >there should be no problem in constructing a new event loop. Right? That approach results in a mode. If you want a modeless event processing model, as the Apple Human Interface Guidelines suggest, such an approach is inappropriate. You should be able to do anything at any time unless there is some pressing reason to prohibit inherently incompatible actions. If you like a calling-type model, something like Common LISP closures might be helpful, as an alternative to tasking. >The question I have hear (sic) is not so much "buying" into the cheap multitasking >(or even sub-event processing), but rather the manner of getting out of it >when the subtask is done. Is there a return value from this other task or >does the task signal its parent with a new event? Assume that the reason for >invoking the other task was to get information from another "process" (user, >database, whatever) and construct an object from that information that the >current task can work with. What should be the method of giving this object >back to the parent task? You fork off a task when there's no need to wait for the result. Suppose the application can open various kinds of documents, but opening may be time-consuming. Having initiated opening of a document, the user should be free to make further selections and open more documents while the first document opens. It's OK to call a subroutine that takes time, but not from the main event loop. The idea is not to take control away from the user. >One naive question, though. Define "smart" dispatcher? One which supports preemption, priorities, time-slicing, and wait/send (or P/V) type operations. A dumb dispatcher can only transfer control at predefined points. John Nagle
davidm@uunet.UU.NET (David S. Masterson) (10/10/89)
In article <14004@well.UUCP> nagle@well.UUCP (John Nagle) writes:
That approach results in a mode. If you want a modeless event
processing model, as the Apple Human Interface Guidelines suggest, such an
approach is inappropriate. You should be able to do anything at any time
unless there is some pressing reason to prohibit inherently incompatible
actions.
How can I get hold of the Apple Human Interface Guidelines? Does it make
sense in an object-oriented world (particularly C++)? How much analysis of
the proposed application is required for this model (it doesn't sound like
much, just a particular mindset that I haven't assimilated yet with C++ in
mind). It seems to me that having a "pressing reason" would be more the norm
in most situations (again, probably a mindset problem).
You fork off a task when there's no need to wait for the result.
Suppose the application can open various kinds of documents, but opening
may be time-consuming. Having initiated opening of a document, the user
should be free to make further selections and open more documents while the
first document opens.
Would not these subtasks also have event loops of their own? There's
something recursive in this definition that I'm having trouble following. In
the C++ paradigm, would opening a document be considered constructing an
object or more of a message to an object that was already constructed (the
document opener task)?
David Masterson
uunet!cimshop!davidm
nagle@well.UUCP (John Nagle) (10/11/89)
In article <CIMSHOP!DAVIDM.89Oct9120329@uunet.UU.NET> cimshop!davidm@uunet.UU.NET (David S. Masterson) writes: >How can I get hold of the Apple Human Interface Guidelines? Buy the book, "Apple Human Interface Guidelines", (no author named), Addison-Wesley, 1986, ISBN 0-201-17753-6. >Does it make sense in an object-oriented world (particularly C++)? Modern thinking on user interfaces is that the interface design drives the internals, not the other way round. >How much analysis of >the proposed application is required for this model (it doesn't sound like >much, just a particular mindset that I haven't assimilated yet with C++ in >mind). A lot. This isn't easy. >It seems to me that having a "pressing reason" would be more the norm >in most situations (again, probably a mindset problem). Finding "pressing reasons" to lock the user into a mode is a sign of a bad design. The user ought to be able to do anything at any time that is meaningful to do, even though this may be inconvenient for the application implementor. >Would not these subtasks also have event loops of their own? They might, but their events would be messages from a higher level event handler. Normally, a subtask shouldn't capture the main event processing, since this would lock out the user from doing all the things normally possible at the top level. John Nagle
alan@oz.nm.paradyne.com (Alan Lovejoy) (10/14/89)
In article <13929@well.UUCP< nagle@well.UUCP (John Nagle) writes:
<
< What you really need is serious concurrency support. Here's why.
<
< In principle, if one has cheap multitasking (called, variously,
<"threads", "lightweight processes", or "weak fork"), an elegant
<solution is for events which will require processing beyond the
<current event to fork off a new task to handle them, requesting that
<related events be forwarded to that task. The task can have lots of
<context, and lots of "auto" storage-class (in the C sense) objects.
<
< It helps if Ada-like exception handling is available. This
<provides a clean way to bail out with proper unwinding when necessary.
<The combination of multitasking, destructors, and exception processing
<makes cleanup almost painless.
<
< Also essential is automatic multitasking interlocks, or "monitors".
<The idea is that if you want to access data shared with another task,
<you must call an access function of a class that is declared as allowing
<object sharing across task boundaries. When one task has control inside
<a function of such a class, other tasks are blocked if they call a
<function of the class. This protects shared data automatically.
<
< Now how do we get multithread C++?
Gee, this reminds me of something... Perhaps some other programming language
I used at one time... Oh! I know, it's like Modula-2! Or is it? Let's see:
Lightweight processes, check. Monitors, check. Exception handling...well,
Modula-2 doesn't have exception handling. Oh well. It doesn't have classes,
constructors or destructors either. I guess you can't have everything.
My impression is that Modula-2's threads are seldom used, for some reason.
Whether this is due to a problem with Modula-2, with the M2 implementation
of threads/monitors, with the Modula-2 user community, or simply indicative
of the usefulness of threads, I couldn't really say.
Of course, exception handling can be kludged-up using setjmp/longjmp. Monitors
and threads require compiler help, or at least extensive non-portable work
with asm(). P&V operations can be used to establish critical sections,
instead of the more elegant "monitor" abstraction.
All things considered, it would seem best to put support for threads/monitors
in the compiler--provided threads/monitors would actually be useful to a
significant community of programmers. Whether this is the case is not clear,
at least to me.
____"Congress shall have the power to prohibit speech offensive to Congress"____
Alan Lovejoy; alan@pdn; 813-530-2211; AT&T Paradyne: 8550 Ulmerton, Largo, FL.
Disclaimer: I do not speak for AT&T Paradyne. They do not speak for me.
Motto: If nanomachines will be able to reconstruct you, YOU AREN'T DEAD YET.