Re: agents, await and Swing thread

2010-09-07 Thread Mark Nutter
Just a quick thought (and before I've had my coffee no less!), but I
think what I'd do is replace the boolean *end-search* with a
*search-state* var that could be either :idle, :running or :stopping.
Then in search-stops, just set *search-state* to :stopping -- you
don't need to actually wait for the agents to finish, you just need to
know that the current condition is waiting for the search to end so
you don't quit the app or start a new search until the cleanup is
finished. Then when you do hit some task that needs to wait until the
agents are done, you can go ahead and await the agents (i.e. if you're
quitting and it doesn't matter if there's a hang), or spawn a thread
that will await the agents before starting the new search. You could
also run a cleanup thread that would check the state of your search
agents and set the *search-state* from :stopping back to :idle once
all the search agents had finished.

Mark

-- 
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


Re: agents, await and Swing thread

2010-09-07 Thread Alessio Stalla
On Sep 6, 5:48 pm, K. kotot...@gmail.com wrote:
 Hello,

 I've got a concurrency problem and it's not really clear to me how to
 solve it. I have a Swing GUI doing a search in background with agents
 and the results are displayed one after the other, also in background.

 Here is, largely simplified, how I do it:

 (defvar- *end-search* (atom false))

 ;; this will be called from a Swing listener, when the user clicks on
 the 'Search' button
 ;; so this is called from the swing thread
 (defn on-search-begins []
    ;;
    (reset! *end-search* false)
    (send *search-agent* do-search))

 (defn do-search [state]
    ;; while (deref *end-search*) is false and while there are results
 for the search, do
    (do-swing
      ;; we are not in a swing thread within the agent, so we need to
 call do-swing
      (display-result swingview result)

      ;; search ends? yes, then
      (do-swing
        (display-search-is-ended swingview)))

 When the user clicks on the 'Stop' button, the following function will
 be called from the Swing thread:

 (defn search-stops []
   (reset! *end-search* true)
   ;; NOW we need to wait for the agents to stop
   (await *search-agent*))

 The problem is: the call to await results in a deadlock. I suspect
 this is because the call to await is made from the Swing thread, and
 once the value of the *end-search* atom is set to true the agent try
 to access the Swing thread but can't because the thread is waiting.

 What solution would you propose to solve this problem?

My 2 cents: move the processing of user actions off the Swing thread
(the EDT) and leave there only the stuff that interacts with the GUI
(which I suppose is what your do-swing already does). Even without a
deadlock it's bad practice to make long blocking calls in the EDT
because that will freeze the GUI.

-- 
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


Re: agents, await and Swing thread

2010-09-07 Thread Laurent PETIT
Hi,

Several questions / thoughts:

2010/9/6 K. kotot...@gmail.com:
 Hello,

 I've got a concurrency problem and it's not really clear to me how to
 solve it. I have a Swing GUI doing a search in background with agents
 and the results are displayed one after the other, also in background.

 Here is, largely simplified, how I do it:

 (defvar- *end-search* (atom false))

 ;; this will be called from a Swing listener, when the user clicks on
 the 'Search' button
 ;; so this is called from the swing thread
 (defn on-search-begins []
   ;;
   (reset! *end-search* false)
   (send *search-agent* do-search))

Mmm, an agent without state always rings a bell in my head. There's a
smell of abuse of the agent concept here. Aren't you just using it
for its commodity to start a new thread. If so, you could as well
just use a future, for example, and then you'll have simpler
semantics. Or you could just (Thread/start) your fn (but then you
introduce java clearly in the code, so maybe just using a future is
the right balance).
Agents carry with them a lot of semantics, so readers of you code may
have unsatisfied expectations on your usage ... until they get it
and think: ok it's just an 'agent abuse'.

 (defn do-search [state]
   ;; while (deref *end-search*) is false and while there are results
 for the search, do
   (do-swing
     ;; we are not in a swing thread within the agent, so we need to
 call do-swing
     (display-result swingview result)

As said by others, I suppose result is computed outside the do-swing
form so that the Swing thread is blocked as few as possible


     ;; search ends? yes, then
     (do-swing
       (display-search-is-ended swingview)))


 When the user clicks on the 'Stop' button, the following function will
 be called from the Swing thread:

 (defn search-stops []
  (reset! *end-search* true)
  ;; NOW we need to wait for the agents to stop
  (await *search-agent*))

It would be interested to know in the first place why you have to add
this call to await at all ?

Anyway, to just answer your question, maybe your
(display-search-is-ended swingview) call could be placed right after
the (await) call, but in another thread ? As in
(defn search-stops []
  (reset! *end-search* true)
  (future (await *search-agent*) (display-search-is-ended swingview)))


But all in all, I'm not sure the overall smells indicate that there
must be another way, probably radically differently structured, to do
all this. I'm thinking about something with watchers on refs /
atoms...

-- 
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