Hey again,
Here is a little example of CL-STM in action.
;; This is just like `defclass', but the slots are transactional.
;; Reading and writing will be done to the transaction log, to be
;; commited later.
STM> (deftransactional-class counter ()
((count :accessor count-of
:initarg :count
:initform 0)))
COUNTER
STM> (defvar *counter* (new 'counter))
#<COUNTER #x8687EDE>
;; Notice, that the slot value is actually a transactional variable.
STM> (count-of *counter*)
#<STANDARD-TVAR #x8687C6E>
;; This is the real value of it, which corresponds to the initform.
STM> (value-of (count-of *counter*))
0
;; `deftransaction' is just like `defun', but when passed arguments,
;; it returns a transaction to be executed by atomic.
STM> (deftransaction increment (counter)
(incf (count-of counter)))
INCREMENT
;; Here is the transaction. Transactions can be composed sequentially
;; and alternatively.
STM> (increment *counter*)
#<STANDARD-TRANSACTION #x85ED356>
;; But, we'll just run it for now in a separate thread.
STM> (atomic (increment *counter*))
#<PROCESS Anonymous(11) [Active] #x86070CE>
;; When commiting, we try to lock each transactional variable. Then
;; we check to see if the variables read in the transaction are the
;; same as the real ones. Then we update the real value. Any threads
;; that are waiting for the variable to change are woken up.
;; Regardless of what happens, the acquired locks are always released.
--TIME MARK 2006-06-14--
17:34 STM-LOGGER/+DRIBBLE+: Committing transaction
17:34 STM-LOGGER/+DRIBBLE+: Acquired lock #<RECURSIVE-LOCK [ptr @
#x302700] #x85A84EE>
17:34 STM-LOGGER/+DRIBBLE+: Version 0 is valid
17:34 STM-LOGGER/+DRIBBLE+: Value updated to 1
17:34 STM-LOGGER/+DRIBBLE+: Version updated to 1
17:34 STM-LOGGER/+DRIBBLE+: Notified threads waiting on
#<STANDARD-TVAR #x85A8526>
17:34 STM-LOGGER/+DRIBBLE+: Transaction log committed
17:34 STM-LOGGER/+DRIBBLE+: Released lock #<RECURSIVE-LOCK [ptr @
#x302700] #x85A84EE>
;; We'll acquire the lock of the variable
STM> (acquire-lock (lock-of (count-of *counter*)))
T
;; And we'll run the transaction again. This time you can see that
;; the lock couldn't be acquired and so the transaction wasn't
;; committed. However, the thread is still running, waiting for the
;; variable to change and have another go committing.
STM> (atomic (increment *counter*))
#<PROCESS Anonymous(12) [Active] #x860031E>
17:34 STM-LOGGER/+DRIBBLE+: Committing transaction
17:34 STM-LOGGER/+DRIBBLE+: Couldn't acquire lock #<RECURSIVE-LOCK
[ptr @ #x302700] #x85A84EE>
17:34 STM-LOGGER/+DRIBBLE+: Transaction log not commited
;; Now we release the lock
STM> (release-lock (lock-of (count-of *counter*)))
NIL
;; These are the current transaction logs waiting for the
;; variable/slot `count'.
STM> (waiting-for (count-of *counter*))
(#<STANDARD-TLOG #x86005A6>)
;; Now we wake them up! As you can see the previous transaction that
;; failed is rerun again, and this time it succeeds!
STM> (mapc #'unwait (waiting-for (count-of *counter*)))
(#<STANDARD-TLOG #x86005A6>)
17:34 STM-LOGGER/+DRIBBLE+: Committing transaction
17:34 STM-LOGGER/+DRIBBLE+: Acquired lock #<RECURSIVE-LOCK [ptr @
#x302700] #x85A84EE>
17:34 STM-LOGGER/+DRIBBLE+: Version 1 is valid
17:34 STM-LOGGER/+DRIBBLE+: Value updated to 2
17:34 STM-LOGGER/+DRIBBLE+: Version updated to 2
17:34 STM-LOGGER/+DRIBBLE+: Notified threads waiting on
#<STANDARD-TVAR #x85A8526>
17:34 STM-LOGGER/+DRIBBLE+: Transaction log committed
17:34 STM-LOGGER/+DRIBBLE+: Released lock #<RECURSIVE-LOCK [ptr @
#x302700] #x85A84EE>
;; And now we've atomically incremented the counter twice. Phew!
STM> (value-of (count-of *counter*))
2
Hoan