On Jun 14, 12:20 am, vmargioulas <vxm...@gmail.com> wrote:
> In the example below 256 clients threads put a byte (0-255) to server-
> socket reference var "items",
> then connect to server-socket, write the same byte to socket stream
> and close the connection.
> The server connections threads reads a byte from the socket stream and
> remove it from the var "items".
> At the end of the run i expect the var items to be empty but it is
> not.
> It 's contains a random number of bytes.
> Where is the error?
>
> (ns
>   test-dosync
>   (:import (java.net Socket))
>   (:use clojure.contrib.server-socket))
>
> (def server
>   (let [items (ref nil)
>         server-ref (ref nil)
>         server-fn (fn [ins _]
>                     (let [bt (.read ins)]
>                       (dosync
>                        (ref-set items (remove #(= % bt) @items)))))]
>
>     {:enq (fn [item] (dosync (alter items conj item)))
>      :list-items (fn [] @items)
>      :start (fn [port]
>               (let [socket-server (create-server port server-fn)]
>                 (dosync
>                  (ref-set items nil)
>                  (ref-set server-ref socket-server))))
>      :stop (fn [] (when @server-ref (close-server @server-ref)))
>      }))
>
> (defn start-server [port] ((:start server) port))
> (defn stop-server [] ((:stop server)))
> (defn enq [id] ((:enq server) id))
> (defn list-items [] ((:list-items server)))
>
> (defn client-fn [port #^Byte byte-to-send]
>   #(let [socket (Socket. "localhost" port)
>          outs (.getOutputStream socket)]
>      (try
>       (do
>         (enq byte-to-send)
>         (doto outs (.write byte-to-send) (.flush)))
>       (finally
>        (.close socket)))))
>
> (defn run-test []
>   (try
>    (let [port 10002]
>      (start-server port)
>      (dorun (apply pcalls (map #(client-fn port %) (range 256)))))
>    (finally (stop-server)))
>   (list-items))

This is probably a lot simpler than you may think;

What is happening here is that your run-test function is returning
before the removes have been run since the client functions do not
wait for confirmation from the server before returning. This can
result in ordering like the following
(with 2 client threads)

Client 1 enqueues byte
Client 1 writes byte and flushes
Client 2 enqueues byte
Client 2 writes byte and flushes
Server Thread for Client1 reads byte
Server Thread for Client2 reads byte
Server gets stopped
run-test returns (0 1)
Server Thread for Client1 removes byte
Server Thread for Client2 removes byte.


Of course this is only an example of a multitude of ways that these
can combine, you can add a couple of logging
statements to your functions to see when these things are happening,
and I think you may be quite surprised at
the different orderings that can arise, but remember to take them with
a grain of salt as output isn't immediate either ;)

The crux here is that your are relying on the server functions running
to completion but you are not waiting on the client
side to confirm that this has happened.


- sean

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to