2011-06-19 34 views
7

Tôi có một nhóm các công việc xử lý tương lai từ một hàng đợi liên quan đến việc ghi vào các tệp. Cách thành ngữ để đảm bảo chỉ một tương lai truy cập vào một tệp cụ thể tại một thời điểm là gì?khóa tập tin thành ngữ trong clojure?

Trả lời

8

Cách sử dụng tác nhân thay vì khóa để đảm bảo điều này?

Tôi nghĩ rằng việc sử dụng tác nhân để bảo vệ an toàn được chia sẻ trạng thái có thể thay đổi, bất kể nó có trong bộ nhớ hoặc trên đĩa có nhiều thành ngữ trong clojure hơn là sử dụng khóa hay không.

Nếu bạn tạo một tác nhân tại một thời điểm và gửi quyền truy cập vào đại lý, bạn có thể đảm bảo rằng chỉ trên chuỗi tại thời điểm truy cập tệp đã cho.

Ví dụ như thế này:

(use 'clojure.contrib.duck-streams) 

(defn file-agent [file-name] 
    (add-watch (agent nil) :file-writer 
    (fn [key agent old new] 
     (append-spit file-name new)))) 

(defn async-append [file-agent content] 
    (send file-agent (constantly content))) 

sau đó nối tập tin của bạn thông qua các đại lý:

(async-append "content written to file" (file-agent "temp-file-name")) 

Nếu bạn cần sử dụng đồng bộ các tập tin nó có thể đạt được với chờ đợi. Như thế này:

(defn sync-append [file-agent content] 
    (await (send file-agent (constantly content)))) 
+0

Gọn gàng! Phải mất một chút để có được đầu của tôi xung quanh này. Tôi đã kết thúc bằng cách sử dụng một ref cho một bản đồ có chứa một mục nhập cho mỗi tập tin mở. Giải pháp của bạn trông giống như nó có thể đẹp hơn nhiều. – jhickner

+0

Tôi vẫn chưa rõ về điều gì đó - nếu hai chủ đề cả hai đều gọi async-append và truyền vào cùng tên tệp, thì điều gì sẽ khiến cả hai mở tệp? Dường như cuộc gọi đến tác nhân tệp trong async-append sẽ tạo một tác nhân duy nhất cho mỗi chuỗi, phải không? – jhickner

+0

Xin lỗi vì các hướng dẫn không rõ ràng, tôi muốn tạo một tác nhân tệp cho mỗi tệp và sau đó nối thêm thông qua tính năng thêm đồng bộ hóa hoặc nối thêm tùy thuộc vào bất kỳ khi nào bạn cần thêm đồng bộ hoặc đồng bộ. Bạn có thể giữ cho các đại lý họ có thể trong bản đồ để tìm đại lý chính xác. –

1

Tôi không nghĩ rằng có chức năng tích hợp cụ thể cho điều này trong Clojure nhưng bạn có thể sử dụng các hàm IO java tiêu chuẩn để thực hiện việc này. Điều này sẽ trông giống như sau:

(import '(java.io File RandomAccessFile)) 

(def f (File. "/tmp/lock.file")) 
(def channel (.getChannel (RandomAccessFile. f "rw"))) 
(def lock (.lock channel)) 
(.release lock) 
(.close channel) 
+0

Tôi đã kiểm tra đại lộ này trước, nhưng tiếc là phương pháp này chỉ hữu ích để khóa tệp khỏi quyền truy cập của các quy trình khác. Khi làm việc với nhiều luồng trong cùng một máy ảo, khóa và tryLock cả hai sẽ ném một ngoại lệ nếu một luồng khác trong cùng một máy ảo đã có tệp bị khóa, thay vì chặn cho đến khi tệp có sẵn. – jhickner

4

Tôi sẽ sử dụng lõi Clojure chức năng locking được sử dụng như sau:

(locking some-object 
    (do-whatever-you-like)) 

Đây some-object hoặc có thể là các tập tin riêng của mình, hoặc cách khác bất kỳ đối tượng tùy ý mà bạn muốn đồng bộ hóa trên (có thể có ý nghĩa nếu bạn muốn có một khóa duy nhất để bảo vệ nhiều tệp).

Phía dưới nắp này sử dụng khóa đối tượng JVM tiêu chuẩn, do đó về cơ bản nó tương đương với một khối mã được đồng bộ trong Java.

Các vấn đề liên quan