Hi.
On 13 January I noted that evaluating an expression in the REPL was not possible if there was still a computation underway. I then asked whether this could be fixed.
I was told by Brian Mastenbrook that it required threading, and that some work on it had been done. Raymond Toy replied that threads were not strictly necessary, and that ILISP did it by interrupting the current computation, performing the requested action, and then resuming the computation again. Luke Gorrie said he liked that idea. He also noted that the discussions on threading until that time were not exactly related to my request.
Since then, I haven't really followed the SLIME list that much, nor have I done much with Lisp :(. Now that my summer vacation is here, I decided to catch up, and fetch the latest SLIME. Not only did I find a nice manual, but to my amazement, the following actually works:
CL-USER> (defvar *stop-damnit* nil) *STOP-DAMNIT* CL-USER> (loop until *stop-damnit*) (setq *stop-damnit* t) NIL CL-USER> T
Great job guys! Keep it up. :)
I'd just like to ask if there's anything else I need to know about this functionality. Are there any limitations? Dangers? Which Lisp implementations does it work with?
Regards, Dirk Gerrits
Howdy Dirk,
Dirk Gerrits dirk@dirkgerrits.com writes:
Not only did I find a nice manual, but to my amazement, the following actually works:
CL-USER> (defvar *stop-damnit* nil) *STOP-DAMNIT* CL-USER> (loop until *stop-damnit*) (setq *stop-damnit* t) NIL CL-USER> T
Great job guys! Keep it up. :)
We're glad you like it :-)
I'd just like to ask if there's anything else I need to know about this functionality. Are there any limitations? Dangers? Which Lisp implementations does it work with?
We've added the concept of "communication styles" to incorporate the ideas from that January thread you cited. There's some discussion of them in the "Lisp-side configuration" part of the manual, though I think we should make it more prominent because it's pretty important.
The defaults are:
CMUCL uses a signal handler to process RPCs. If you issue two at once then the second will run "inside" the first on a signal handler, which looks like what your example does.
LispWorks, ACL, and SBCL-with-threads use a separate thread for each request. (Well, almost: the REPL always uses the same thread.)
The rest use either something select()-based or a loop.
Not every style is supported by every backend, but some do support more than one. Exactly which ones is not currently precisely documented :-)
-Luke
Dirk Gerrits wrote:
I was told by Brian Mastenbrook that it required threading, and that some work on it had been done. Raymond Toy replied that threads were not strictly necessary, and that ILISP did it by interrupting the current computation, performing the requested action, and then resuming the computation again.
I would like to point out some dangers associated with both multiple threads and interrupting the current computation, performing the requested action, and then resuming the computation again.
The problem is that the "background process" muts be written to be thread-safe. This means that any globally accessable "objects" that might be undergoing modification by the "background process" must be locked in some manner and the computation performed by the REPL process must respect those locks.
I am providing this information based on my experiences with the Lisp Machine "mouse process" and the care that was required to insure global objects were not modified in an unsafe manner.
Lots of "random" bugs can be caused by ignoring thread safety.
Lynn Quam quam@ai.sri.com writes:
I would like to point out some dangers associated with both multiple threads and interrupting the current computation, performing the requested action, and then resuming the computation again.
The problem is that the "background process" muts be written to be thread-safe. This means that any globally accessable "objects" that might be undergoing modification by the "background process" must be locked in some manner and the computation performed by the REPL process must respect those locks.
Thanks for the warning.
BTW, do Lisp implementations make any guarantees about which actions are atomic? For example, suppose *some-var* is bound to 10 and I type (setq *some-var* 42) in the REPL, will the running process see just the values 10 and 42, or might it inspect *some-var* when the assignment is still going on and see 'garbage'?
Regards,
Dirk Gerrits
Dirk Gerrits wrote:
BTW, do Lisp implementations make any guarantees about which actions are atomic? For example, suppose *some-var* is bound to 10 and I type (setq *some-var* 42) in the REPL, will the running process see just the values 10 and 42, or might it inspect *some-var* when the assignment is still going on and see 'garbage'?
I do not know of any Common Lisp implementation where a SETQ to a global (special) variable is non-atomic. Since the Common Lisp specification (Hyperspec) make no mention of processes, threads, or interrupts, the Common Lisp standard makes NO GUARANTEE about any operation being atomic. The documentation for specific Common Lisp implementations might discuss what operations are guaranteed to be atomic with respect to process switching and interrupts.
Lynn Quam wrote:
I do not know of any Common Lisp implementation where a SETQ to a global (special) variable is non-atomic.
Okay, good to know.
Since the Common Lisp specification (Hyperspec) make no mention of processes, threads, or interrupts, the Common Lisp standard makes NO GUARANTEE about any operation being atomic.
Yeah that's why I said 'Lisp implementations'.
The documentation for specific Common Lisp implementations might discuss what operations are guaranteed to be atomic with respect to process switching and interrupts.
Okay, I guess I'll do some digging. Thanks again.
Regards,
Dirk Gerrits
Lynn Quam quam@ai.sri.com writes:
I would like to point out some dangers associated with both multiple threads and interrupting the current computation, performing the requested action, and then resuming the computation again.
Yes, it must be remembered that threads are complete and utter insanity to begin with. We added threads support in SLIME because everybody else is intent on using them, not because we're crazy enough to do so ourselves :-)
I do find SIGIO practical though. In that case I know that I'm forcing a context-switch and I'm responsible for the consequences, and I do it so infrequently that I've never observed a problem from it. Quite managable compared with e.g. a multithreaded server somewhere doing a thousand context-switches per second without human supervision :-)
-Luke