- Khóa file để bảo vệ quá trình ghi/đọc file không bị tiến trình khác thao tác trên file đó.
- Khóa file còn để đánh dấu một tiến trình đang chạy, tránh để nhiều tiến trình tương tự chạy cùng lúc.
Yêu cầu cơ bản là tiến trình nào khóa file thì phải mở khóa file khi không cần khóa nữa, bất kể tiến trình đó kết thúc bình thường hay đột ngột.
Có nhiều cách để khóa/mở khóa file, dùng công cụ hệ thống hay dùng các gói cài đặt thêm.
1. Thí dụ sau đây khóa file resp.txt, tiến trình khác chỉ có thể đọc
touch resp.txt ( unset 200 exec 200< resp.txt flock -e 200 ## ... read/write resp.txt ... )
resp.txt được mở với file id là 200, sau đó khoá chỉ đọc. Khoá được tự động mở khi khối lệnh thi hành xong.
2. Thí dụ sau đây khóa file để đánh dấu tiến trình đạng chạy
##-- run only one instance --
exec 200>/var/lock/LCK..$(basename $0)
flock -n 200 || { echo Another process running!;exit 1; }
trap "rm -f /var/lock/LCK..$(basename $0)" SIGHUP SIGINT SIGQUIT SIGTERM SIGKILL SIGSTOP
Một dạng thường dùng khác
( flock -n 200 || exit 1 trap "rm -f /var/lock/mylockfile" SIGHUP SIGINT SIGQUIT SIGTERM SIGKILL SIGSTOP ## ... commands executed under lock ... ) 200>/var/lock/mylockfile
Vì hàm flock dùng file ID nên ta tạo file có ID là 200 trong thư mục /var/lock, tên file lock có thể đặt tùy ý hay theo qui ước là LCK..tên_script_đang_chạy. Nếu không tạo được thì thoát (đã có tiến trình tương tự đang chạy). Khi tiến trình đang chạy và khóa file kết thúc, file lock tự động được xóa.
3. Một cách đánh dấu khác nhưng dùng mkdir
lockdir=/var/tmp/myapp if mkdir $lockdir; then # this is a new instance, store the pid echo $$ > $lockdir/PID else echo Job is already running, pid $(<$lockdir/PID) >&2 exit 6 fi # then set traps to cleanup upon script termination trap 'rmdir -r "$lockdir" EXIT # do what you need to
Hàm mkdir gặp lỗi nếu thư mục đã có. Thư mục đánh dấu này cần được xóa khi ứng dụng kết thúc vì bất kỳ lý do gì. Chúng ta dùng hàm trap để bẫy các mã kết thúc của ứng dụng, khi có mã này thì chúng ta xóa thư mục đánh dấu.
4. Một phương pháp khác là dùng option noclobber bằng lệnh set -C, khi đó > sẽ bị lỗi nếu file tồn tại.
set -C lockfile="/tmp/locktest.lock" if echo "$$" > "$lockfile"; then echo "Successfully acquired lock" trap 'rm "$lockfile"' EXIT # do work else echo "Cannot acquire lock - already locked by $(cat "$lockfile")" fi
Chú thích
Khi reboot thì chương trình kết thúc mà không phát sinh mã thoát, vì vậy trap không thể xóa file giúp. Để khắc phục tình trang này, chúng ta cần tạo file/folder đánh dấu ở trong các thư mục được tự động reset khi khởi động lại, như /tmp, /run …