2016年7月3日日曜日

flock関数について調べてみた

いきなりステーキとflock関数


「いきなりステーキ」で、300gのステーキをモリンと食って、ビールをしこたま飲んだ挙句、尿酸値Full Maxな感じで倒れそうですが、flockで目が覚めた最近です。Solarisでゴニョゴニョやっているとちょいちょいflock関数でハマる、Solarisにはflock関数がない。面倒くさいからいつも逃げていたのですが今回はしっかり理解しようと思って、ちょっと調べてみた。だいたい、時間がたつとほぼ忘れますが...



flockはアドバイザリロック


ロックを取得するプロセスやスレッドが協力して動作するロック方式で、強制力のないロック方法です、ルールを守らないプロセスやスレッドが共有リソースへでたらめにアクセスした場合リソースは壊れる可能性があるので気をつけてください

Linuxのflock関数


詳しい関数の説明はmanページを見てくださいということでサンプルはgithubへ置きましたのでcloneしてmakeしてください。

https://github.com/calimakvo/flock.git

cuomo@karky7 ~/flock $ tree 
.
├── Makefile
├── flock.c      「共有ロック(LOCK_SH)」
├── flock_ex.c   「排他ロック(LOCK_EX)」
└── flock_nonblock.c 「ノンブロッキング排他ロック(LOCK_EX|LOCK_NB)」

ロックを確認する


「共有ロック」を使ったロック方式、シグナルをセットした後、flock関数を呼ぶ出すときに「LOCK_SH」を指定して呼び出す。ターミナルから複数起動しても直ぐにロックを取得できる、Read Lockで書き込みする奴が何もいなければ問題ない。
* 1つめ実行
cuomo@karky7 ~/flock $ ./flock
Lock success.
lock fd = 3
main loop..
main loop..
main loop..
..
* 2つめを別ターミナルから実行
cuomo@karky7 ~/flock $ ./flock
Lock success.
lock fd = 3
main loop..
main loop..
main loop..
..

「共有ロック」なので「共有ロック」同士のプロセスなのでロックはすぐとれる

次に2つの「共有ロック」プロセスが動いているところへ「排他ロック」なプロセスを起動してみる
cuomo@karky7 ~/flock $ ./flock_ex
...ロックがとれないのでflock関数でブロックしている

flock_exがflockでブロックしている状態のまま、最初の2つの「共有ロック」なプロセスをCtrl+Cで終了させると
cuomo@karky7 ~/flock $ ./flock_ex
Lock success.
lock fd = 3
main loop..
main loop..
main loop..
...

「排他ロック」のプロセスがロックを取得して実行し出す、その後「共有ロック」なプロセスを複数起動してから...
というような感じで交互に別ターミナルから実行すれば動作が掴めると思います。

LOCK_NBについて


flockで寝てもらいたくない場合に利用するフラグです。flock関数に(LOCK_NB)フラグをor演算子で追加指定して呼び出すと、ロックが取得できなくてもflock関数でブロックせず「EWOULDBLOCK」を返してくる呼び出し方法です。

flock関数とsignal


flock関数が「EINTR」を返すケースっていうのがあります、これはflock関数が呼び出されてブロックしている間にそのプロセスにシグナルが到着した場合、flock関数が中断されエラーで帰ってくる場合があるので、エラーでも「EINTR」の場合はもう一度呼び出してやる必要があります。
flock_exがブロックする状況を作って、別ターミナルからSIGUSR1をflock_exへ送ると、15661はflock_exのPIDです
cuomo@karky7 ~ $ kill -USR1 15661

ロックしているflock_exのターミナルへ「EINTR」を受け取って再度flock関数を呼び出したログが出力されます
cuomo@karky7 ~/flock $ ./flock_ex
get SIGUSR1
Retry get lock. 
..

この時のシグナル動作の注意点としては、通常のsignal関数でSIGUSR1をセットしただけでは「EINTR」で帰って来ないと言うことです(Linuxでの動作なのでBSDあたりだと確認とっていませんが...)、と言うことでPosix的なsigaction関数でシグナルをセットする必要があります。

flock関数とNFS


flock関数はNFS経由で利用した場合はしっかり動かないような処理系があるそうなのでご注意ください、ちなみにSolarisのNFSをLinuxでマウントして同じロック検証(ロックファイルはNFS上に作成)をやって見ましたが問題は起こりませんでした、Linuxのマウント設定とSolarisのNFS設定を確認してみます。

今後...


で「Solaris関係ないじゃん」って言われそうですが、これがfcntl関数へ続く予定です、暫くお待ちください...


汚いコードですみません..


0 件のコメント:

コメントを投稿