Forum OpenACS Development: Re: Thread safety of OpenACS vs RoR et al.

Posted by Stan Kaufman on
At the risk of revealing how shallow my Pool of Understanding is on all this ("Dammit, Jim, I'm an app developer not a systems engineer!"), to what extent does a typical OpenACS installation use the multi-threaded facilities that Tcl and AOLServer make possible (or is this a function of loading)? None of the package code appears to have any explicit design decisions based on the question of "should this be multi-threaded or not?". Is that because OpenACS is intrinsically multi-threaded and concurrency simply comes for free with OpenACS?
Posted by Andrew Piskorski on
Stan, yes, that's basically correct. The multi-threading largely comes for free, for typical OpenACS app development, you don't need to think much about it, and the parts you do need to think about have a gentle learning curve.

Note that you probably do need to think about concurrency in the way you write your SQL insert or update statements - that's got nothing to do with AOLserver nor Tcl per se. But Oracle and PostgreSQL both have MVCC and Transactions, which help enormously in dealing with database concurrency.

AOLserver uses multi-threading implicitly and rather pervasively. However, as an OpenACS or AOLserver/Tcl programmer you normally don't need to think about this. This is the beauty of the AOLserver and Tcl thread model and APIs vs. nasty low-level stuff like the POSIX thread APIs.

Note that Tcl's threading model is default shared-nothing. (While the POSIX threads underneath are default shared everything. The C code deals with that.)

In AOLserver each page hit runs in its own connection thread with its own Tcl interpretor. (The actual architecture is a bit more complex than that, but that statement is true as far as it goes.) You program what each page does essentially as if it was a single threaded application. When you as the programmer use nsv_get, nsv_set, or ad_schedule_proc, you are using AOLserver's multi-threaded services, but typically there's nothing special you need to do because of that. Each single nsv_* operation is atomic, the mutex locking is done automatically underneath.

With OpenACS you would typically not use lower level Tcl multi-threading stuff like ns_mutex or ns_cond - but those features are there if you need them.

Now, say you want to read a the value 5 from and nsv, increment it by 1, and then write it back. Or more realistically, use nsv_get to read a Tcl list, lappend to it, and then use nsv_set to write it back. Ah, now you do need to think about threads and concurrency, at least a little bit. Another thread could be reading or writing that nsv at the same time, and correct operation depends on a sequence of two nsv_* commands being atomic, not just one. So you need to manually protext access to the nsv with a mutex lock. Or better yet, upgrade to Zoran's Tcl Threads Extension which gives you an atomic tsv::lappend command, etc.