Как запустить два потока и ждать их - PullRequest
2 голосов
/ 27 декабря 2011

Я могу запустить два потока, и они работают, но синхронно.Чего мне не хватает, чтобы эти потоки запускались независимо?

main, thread и output

(defn -main 
    [& args]
    (do
        (let [grid-dim-in [0 5]
              mr1-pos     [\N 2 4]
              mr2-pos     [\N 1 5]
              mr1-movs    "LMLMMRMM"
              mr2-movs    "RMRMMMLM"]

            (reset! grid-dim grid-dim-in)
            (reset! mr1-id {:mr1 mr1-pos})
            (reset! mr2-id {:mr2 mr2-pos})

            (.start (Thread. (rover-thread mr1-id mr1-movs update-work-block)))
            (.start (Thread. (rover-thread mr2-id mr2-movs update-work-block))))))

(defn rover-thread [id movs update-ref]
    (let [id-key (keys @id)
          id-vals (vals @id)]
        (doseq [mov movs]
           (println "Rover " id-key " is moving ")
           (let [new-mov (determine-rover-move (first id-vals) mov)]
               (move-rover id new-mov update-ref)
               (print "Rover ")
               (print (first id-key))
               (print " is at ")
               (println new-mov)
               (Thread/sleep (rand 1000)))))

Rover :mr1 is at [E 2 4]
Rover  (:mr1)  is moving 
Rover :mr1 is at [N 2 5]
Rover  (:mr1)  is moving 
Rover :mr1 is at [N 2 5]
Finished on Thread[main,5,main]
Rover  (:mr2)  is moving 
Rover :mr2 is at [E 1 5]
Rover  (:mr2)  is moving 
Rover :mr2 is at [N 1 6]

Ответы [ 2 ]

7 голосов
/ 27 декабря 2011

Внимательно посмотрите на эти две строки:

(.start (Thread. (rover-thread mr1-id mr1-movs update-work-block)))
(.start (Thread. (rover-thread mr2-id mr2-movs update-work-block))))))

Этот код сначала оценивает (rover-thread mr1-id mr1-movs update-work-block) и передает результат этого конструктору Thread, а это не то, что вам нужно.

Вот простая функция, иллюстрирующая принцип. Это не работает, потому что (f ...) вычисляется до того, как его результат передается конструктору Thread:

(defn run-thread-thing-wrong []
  (let [f (fn [n s]
            (doseq [i (range n)]
              (prn s i)
              (Thread/sleep (rand 1000))))]
    (.start (Thread. (f 10 "A")))
    (.start (Thread. (f 10 "B"))))
  nil)

Вот версия, которая работает. функция передается конструктору Thread вместо:

(defn run-thread-thing []
  (let [f (fn [n s]
            (doseq [i (range n)]
              (prn s i)
              (Thread/sleep (rand 1000))))]
    (.start (Thread. (fn [] (f 10 "A"))))
    (.start (Thread. (fn [] (f 10 "B")))))
  nil)

Примечание: вместо (fn [] ....) вы можете использовать краткую форму #(....) для анонимных функций.

Вот еще одна версия, которая делает то же самое, но с future вместо создания потоков вручную:

(defn run-thread-thing []
  (let [f (fn [n s]
            (doseq [i (range n)]
              (prn s i)
              (Thread/sleep (rand 1000))))]
    (future (f 10 "A"))
    (future (f 10 "B")))
  nil)

Обратите внимание, что в этом случае вы передаете форму future вместо функции.

1 голос
/ 30 декабря 2011

Кажется, это действительно хорошее место, чтобы использовать агент Clojure .Я не квалифицирован, чтобы полностью объяснить, как их использовать, но действительно хороший пример их использования можно найти здесь .Запускать потоки с помощью агентов очень просто, и я думаю, что это более идиоматично.

Код будет выглядеть примерно так:

(def rover1 (agent [mr1-posn mr1-movs mr1-id])) 
(def rover2 (agent [mr2-posn mr2-movs mr2-id])) 
(defn rover-behave [[posn movs id]]
  (send-off *agent* #'rover-behave)
  (. Thread (sleep 1000))
  (let [new-mov (determine-rover-move posn movs id)
        new-posn (posn-after-move posn new-mov)]
    ;return value updates state of agent
    [new-posn movs id]
  )
)
(send-off rover1 rover-behave)
(send-off rover2 rover-behave)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...