最近、小規模プロジェクト用のシェルスクリプトを作成しようとしましたが、何らかの理由でコマンドがflock
機能しませんでした。サブシェルからアトミックに呼び出してバックグラウンドに入れるたびに、他のプログラムがロックされたファイルを読み書きできるようです。
カンクンセッション:
guest@guest ~ $ touch ./temp
guest@guest ~ $ ( flock -x 3 && sleep 99999999999; ) 3>./temp &
[1] 22874
guest@guest ~ $ cat ./temp
guest@guest ~ $ echo this is a test >./temp
guest@guest ~ $ cat ./temp
this is a test
guest@guest ~ $ jobs
[1]+ Running ( flock -x 3 && sleep 99999999999 ) 3>./temp &
guest@guest ~ $ bash --version
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
私は「群集」プログラムの内部に関連する非常に単純なものを見逃したようですが、それが何であるかわかりません。
答え1
flock
コラボレーションロック方式のアドバイザリロックを行います。これは、協力しないとロックを無視できることを意味します。タスクを実行する前にロックを要求し、タスクが完了した後にロックを解除する方法で協力できます。これは(必ず)ロックファイル自体ではなくロックで保護されている操作です。
~からflock(2)
手動私のシステムでは:
アドバイザリロックを使用すると、協調プロセスはファイルに対して一貫した操作を実行できますが、一貫性は保証されません(つまり、プロセスはアドバイザリロックを使用せずにファイルにアクセスし続けるため、矛盾が発生する可能性があります)。
次のスクリプトを考えてみましょう。
#!/bin/sh
( flock -x 9 || exit 1
echo '1: Locking for 5 secs'; sleep 5; echo '1: Done' ) 9>/tmp/lock &
sleep 1
echo '2: Will now attempt to get lock'
( flock -x 9 || exit 1
echo '2: Got lock' ) 9>/tmp/lock
# Since the second flock call only performs one operation, the whole last
# subshell may be replaced by just
# flock -x /tmp/lock -c echo '2: Got lock'
#
# (-x and -c are not needed, a lock is exclusive ("write lock")
# unless -s is used to create a shared lock ("read lock"),
# and the -c is optional)
出力:
1: Locking for 5 secs
2: Will now attempt to get lock
1: Done
2: Got lock
バックグラウンドプロセスがロックを取得し、他の呼び出しがロックをflock
解除するには、ロックが解除されるのを待つ必要があることがわかります。
また、ここで保護されるのは、ロックされたファイルではなく、echo
排他性が保証されるサブシェルの操作であることに注意してください。特に、ロックファイルは、非協調的なプロセスの書き込みまたは読み取りから保護されません。
これはflock
、この例では、ロックによって、/tmp/lock
各サブシェルのタスク(ファイルまたは他の共有データリソースに対するタスク)が他のサブシェルの競合するタスクと混在しないことを保証します。どのflock
/tmp/lock
ファイルをロックするための別のプログラムとして一緒に使用してください。
上記の最後の段落を説明するために、可能であれば、上記のスクリプトを2つの異なる端末で同時に実行し(休止時間を少し増やすことができます)、両方の競合スクリプトが適切にロックを取得することを確認します(お互いを待ちます)。バックグラウンドプロセスでロックが要求されるため、ロック可能2つのスクリプトインスタンスを同時に実行すると、スクリプトで指定された順序で取得できません。
あなたの例では、インタラクティブシェルは次のとおりです。ロック機構に協力しない。これがバックグラウンドサブシェルがロックを保持していてもファイルを読み書きできる理由です。
また、すべてのファイルシステムがflock
C ++(またはそれに対応するCライブラリflock()
)を使用したファイルロックをサポートしているわけではありません。たとえば、ネットワークファイルシステムAFSとNFSには問題がある可能性があります。バラよりhttps://en.wikipedia.org/wiki/File_locking#Problems