使用原子和未来在我的Clojure计划中创造竞争条件

时间:2015-11-11 05:21:49

标签: json multithreading clojure race-condition

我有一个用Clojure编写的Web服务。它实现了一个简单的GET方法,它返回一个JSON对象,表示路由器的当前位置和不同的时间计数器。

我的代码有一堆原子来跟踪时间。每个原子代表机器在给定时间可能正在进行的不同活动。例如:校准,空闲,卡住或工作:

(def idle-time (atom 0))
(def working-time (atom 0))
(def stuck-time (atom 0))
(def calibration-time (atom 0))

接近结束时,我有一个循环,每隔15秒更新位置和时间计数器:

(defn update-machine-info []
  (let [machine-info (parse-data-files)]
    (update-time-counters machine-info)
    (reset! new-state (merge machine-info
                             {:idleCounter        @idle-time
                              :workingCounter     @working-time
                              :stuckCounter       @stuck-time
                              :calibrationCounter @calibration-time}))))

(loop []
  (future
    (Thread/sleep 15000)
    (update-machine-info)
    (recur)))

目前此代码遇到竞争条件,这意味着位置和时间计数器未更新。但是,Web服务仍然会响应正确的JSON响应,尽管它具有旧值。

Web Service正在使用Cheshire生成映射到JSON,这里是我的GET实现:

(defroutes app-routes
  (GET "/" [] (resource :available-media-types ["application/json"]
                        :handle-ok (generate-string (get-machine-information))))
  (route/not-found "Not Found"))

我应该使用ref而不是原子吗?我正确使用未来吗?是(Thread / sleep 15000)导致问题,因为原子是异步的吗?

如果您在我的代码中看到明显的错误,请告诉我。

2 个答案:

答案 0 :(得分:1)

我不认为你可以在未来可靠地重复出现在未来之外的循环(不完全确定),但为什么不尝试这样的东西呢?

<View... android:visibility="gone"/>
or
<View... android:visibility="invisible"/>

这样循环/重复停留在同一个线程中。

除此之外,如果更新机器计数器抛出异常,循环将停止,您将永远不会看到异常,因为永远不会取消引用未来。代理(http://clojure.org/agents)可能更适合这种情况,因为您可以注册错误处理程序。

答案 1 :(得分:0)

我认为正在发生的事情是,您调用期货的过程在您的期货实际执行之前终止。对于你的所作所为,期货可能是错误的构造类型。我也不认为您的循环未来录音序列正在按照您的想法进行。

这里有很多猜测,因为不清楚你究竟在哪里定义和调用你的代码。我想您可能想要使用类似代理的东西,您需要在根进程中设置它们,然后在返回响应之前在处理程序中向它们发送消息。