I learned today that PLT Scheme actually has two kinds of thread-local storage boxes: parameters, which everybody knows about, and thread-cells, which as far as I can tell are not well-known at all even among PLT developers. The difference is very subtle: parameters are attached to a continuation and thread, thread-cells are only attached to a thread. That makes no sense, I know, but maybe it will with a code example:
This prints out:
The second half of the printout is the interesting part. It shows that a continuation stores the parameter settings in effect when it is captured and carries them to new threads; it does not, on the other hand, capture the current values of thread-cells. This makes thread-cells, despite their obscurity, the better choice for implementing a lot of things; for instance, in an OS-like program that uses continuations to represent user processes and threads to represent particular slices of computation, thread-cells are the right abstraction for holding onto the OS resources that are particular to a thread.
That example wasn't pulled out of thin air, of course. It's actually how I came to learn about thread-cells at all, in fact; the PLT web server had an odd bug that cropped up because some resources that should be thread-cells were parameters instead, the result of which was that servlets that tried to save continuation objects occasionally found that when they eventually threw to them the servlet would die abruptly.
This is now fixed, and to celebrate I released a somewhat nifty new PLaneT package that highlights the power of being able to write abstractions over web interaction patterns rather than just web pages: resume.plt.
(define p (make-parameter #f))
(define t (make-thread-cell #f))
(define k #f)
(begin
(thread
(lambda ()
(parameterize ((p 'thread-one))
(thread-cell-set! t 'thread-one)
(display "In thread 1:")
(newline)
(let/cc my-k (set! k my-k))
(printf "param: ~a, tc: ~a\n" (p) (thread-cell-ref t)))))
(sleep 1)
(thread
(lambda ()
(parameterize ((p 'thread-two))
(thread-cell-set! t 'thread-two)
(display "In thread 2, throwing to a continuation created by
thread 1:")
(newline)
(k 'dontcare)))))
This prints out:
In thread 1:
param: thread-one, tc: thread-one
In thread 2, throwing to a continuation created by thread 1:
param: thread-one, tc: thread-two
The second half of the printout is the interesting part. It shows that a continuation stores the parameter settings in effect when it is captured and carries them to new threads; it does not, on the other hand, capture the current values of thread-cells. This makes thread-cells, despite their obscurity, the better choice for implementing a lot of things; for instance, in an OS-like program that uses continuations to represent user processes and threads to represent particular slices of computation, thread-cells are the right abstraction for holding onto the OS resources that are particular to a thread.
That example wasn't pulled out of thin air, of course. It's actually how I came to learn about thread-cells at all, in fact; the PLT web server had an odd bug that cropped up because some resources that should be thread-cells were parameters instead, the result of which was that servlets that tried to save continuation objects occasionally found that when they eventually threw to them the servlet would die abruptly.
This is now fixed, and to celebrate I released a somewhat nifty new PLaneT package that highlights the power of being able to write abstractions over web interaction patterns rather than just web pages: resume.plt.