見出し画像

flock() のバグ

 UNIX(最近はほぼ Linux の事になりますが)の flock() 関数(ファンクションコール)にはバグがあって、気が付かないとそこで胃潰瘍になる人が出てくると思われるので、こうして NOTE に記しておきます。

マルチプロセス、マルチスレッドが普及して、とても便利に高速になりましたが、プログラミングもそれに対応してマルチプロセス、マルチスレッドプログラミングが必要となっています。ご存知の通り、マルチプロセス、マルチスレッドプログラミングでは共有メモリによる排他処理が必要ですが、いくつか方法があることもよくご存知のことと存じます。常套手段は、pthread の mutex やセマフォですが、特にファイルシステムの排他制御を行う flock() もあります。UNIX は、処理をファイル入出力を中心に設計されているので、flock() を使った方が簡潔で利便性が高いケースも多々あります。通常の使い方、つまり、自分のプロセスやスレッドがファイルを使用している間、他のプロセスやスレッドがファイルにアクセスできないようにする目的においては特に問題は起こらないのですが、少しシビアな使い方、つまり、高速に切り替えたり、厳密に排他処理を行いたいと思った時は、要注意です。

Wikipedia の「ファイルロック」の項目には、このように書かれてあります。※通常、プログラムを組んている際に関数やクラスの機能を調べるのに Wikipedia を参照する人は稀、というよりはいないと思われるので、中々、気付かないのではないかと思われます。

同じファイルへの(ひとつのプロセスからの)flock呼び出しは、ロックの状態を変更する(共有から排他へ、あるいは排他から共有へ)。しかし、このとき一時的に古いロックを外してから新しいロックをかける。例えば、排他ロックから共有ロックにかけ変えようとしたとき、一瞬の隙をついて別のプロセスが排他ロックをかけたら、元々ロックをかけていたプロセスが締め出されてしまう。

https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%AD%E3%83%83%E3%82%AF#%E5%95%8F%E9%A1%8C%E7%82%B9

こんなのバグだと思うのですが、調べてみると分かる通り、flock() はアドバイザリーロックと言う位置づけです。つまり、アドバイス、助言です。Solaris では flock() は実装されていないと書いているウェブサイトもあります。私もしばらく悩みましたから、こんな不完全な排他制御機能は、無いほうがいいとも思います。Sun Micorosystems の技術者はそう判断したのでしょう。なければ通常の mutex やセマフォを利用します。実際、この問題に気が付いた後は、mutex を使ってプログラムを直しました。それまでは、一緒に開発をしていた人達から白い目で見られるはめになりました。単体テストでは出てこなかったのです。私の場合は、ミリセコンド単位で排他制御をしていたので、プロセス同士の制御タイミングが徐々に近づいて行き、ついにクリティカルなタイミングでデッドロックしていました。

最後に

恐らく、ロックファイルよりはましという位置づけなのでしょう。いつまで経っても修正されないということは、ファイルシステムの構造上、厳密な制御はできないのだと思われます。flock() にはバグがあり、それはアドバイザリーと呼ばれていますが、高速な切り替えや厳密な排他制御には対応していないので、注意が必要です。

以上



この記事が気に入ったらサポートをしてみませんか?