Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure mutable storage types

It sounds like you are really getting Clojure! good job :)

Vars have a "root binding" visible in all threads and each individual thread can change the value it sees with out affecting the other threads. If my understanding is correct a var cannot exist in just one thread with out a root binding that is visible to all and it cant be "rebound" until it has been defined with (def ... ) the first time.

Refs are committed at the end of the (dosync ... ) transaction that encloses the changes but only when the transaction was able to finish in a consistent state.


I think your conclusion about Atoms is wrong:

Atoms are like Vars but with thread-sharing safety that blocks until the value has changed

Atoms are changed with swap! or low-level with compare-and-set!. This never blocks anything. swap! works like a transaction with just one ref:

  1. the old value is taken from the atom and stored thread-local
  2. the function is applied to the old value to generate a new value
  3. if this succeeds compare-and-set is called with old and new value; only if the value of the atom has not been changed by any other thread (still equals old value), the new value is written, otherwise the operation restarts at (1) until is succeeds eventually.

I've found two issues with your question.

You say:

If an agent is accessed while an action is occurring then the value isn't returned until the action has finished

http://clojure.org/agents says:

the state of an Agent is always immediately available for reading by any thread

I.e. you never have to wait to get the value of an agent (I assume the value changed by an action is proxied and changed atomically).

The code for the deref-method of an Agent looks like this (SVN revision 1382):

public Object deref() throws Exception{
    if(errors != null)
    {
        throw new Exception("Agent has errors", (Exception) RT.first(errors));
    }
return state;

}

No blocking is involved.

Also, I don't understand what you mean (in your Ref section) by

Transactions are committed on calls to deref

Transactions are committed when all actions of the dosync block have been completed, no exceptions have been thrown and nothing has caused the transaction to be retried. I think deref has nothing to do with it, but maybe I misunderstand your point.


Martin is right when he say that Atoms operation restarts at 1. until is succeeds eventually. It is also called spin waiting. While it is note really blocking on a lock the thread that did the operation is blocked until the operation succeeds so it is a blocking operation and not an asynchronously operation.

Also about Futures, Clojure 1.1 has added abstractions for promises and futures. A promise is a synchronization construct that can be used to deliver a value from one thread to another. Until the value has been delivered, any attempt to dereference the promise will block.

(def a-promise (promise))
(deliver a-promise :fred)

Futures represent asynchronous computations. They are a way to get code to run in another thread, and obtain the result.

(def f (future (some-sexp)))
(deref f) ; blocks the thread that derefs f until value is available