概要
UNIX系やPOSIX準拠OSで カーネルが保証するアトミック操作 のカタログ。 マルチスレッドや多プロセス環境 で安全なプログラム作成の基礎。 ロックやミューテックスなし で活用可能な手法。 ファイルシステムやファイルディスクリプタ を対象とした例多数。 NFS等の分散FSでは動作保証外 な点に注意。
UNIXでアトミックにできること
-
カーネルによるアトミック性保証 プログラム上で明示的なロックを使わず、 カーネルが内部で排他制御 する操作 ロック処理による CPU負荷の回避
-
パス名操作(ローカルファイルシステム推奨) NFS等のネットワークFSでは アトミック性保証外 mv -T <oldsymlink> <newsymlink>
- <newsymlink>のターゲットを アトミックに<oldsymlink>へ切替
- 実体は rename(2) システムコール呼び出し
- Mac OS Xのmv(1) ではrename(2)を使わないため非対応 link(oldpath, newpath)
- ハードリンク作成。newpathが既存なら EEXISTエラー
- ファイルロック用途 として利用可能(lsで可視化) symlink(oldpath, newpath)
- シンボリックリンク作成。既存ならEEXISTエラー
- ディレクトリロック にも応用可能
- ダングリングシンボリックリンク (ターゲット消失時)に注意
- inode数は有限資源 rename(oldpath, newpath)
- 同一ファイルシステム内でパス名変更をアトミックに実行
- oldpathが無い場合 ENOENTエラー
- ファイル削除予定時に 自然なロック手法 open(pathname, O_CREAT | O_EXCL, 0644)
- 新規ファイル作成と同時オープン
- 既存なら EEXISTエラー
- 排他処理やタスク担当決定 に活用 mkdir(dirname, 0755)
- 新規ディレクトリ作成。既存ならEEXISTエラー
- ディレクトリ用排他制御 手法
-
ファイルディスクリプタ操作 fcntl(fd, F_GETLK, &lock), fcntl(fd, F_SETLK, &lock), fcntl(fd, F_SETLKW, &lock)
- ファイル領域ごとのロック
- F_SETLKW はロック取得まで ブロック
- Linuxの mandatory locking は競合条件があり非推奨 fcntl(fd, F_GETLEASE), fcntl(fd, F_SETLEASE, lease)
- 他プロセスによる オープン/トランケート時SIGIO通知
- 通知後は F_SETLEASE, F_UNLCK でリース解除
- fcntl(fd, F_NOTIFY, arg) は同期用途には不向き mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
- ファイル内容をメモリマップ し、複数プロセス間で共有
- msync(addr, length, MS_INVALIDATE) でデータ同期
- mmap(2), msync(2)
-
仮想メモリ操作(GCC Atomic Builtins) __sync_fetch_and_add, __sync_add_and_fetch, __sync_val_compare_and_swap
- フルバリア付きアトミック操作
- ロックフリーアルゴリズムの基礎
- GCC組込関数 として提供
注意点・補足
- NFS等分散FSではアトミック性保証外
- 複数カーネルが絡むため、 ローカルFS限定 で利用推奨
- inodesは有限資源
- 大量ロックやシンボリックリンク利用時は枯渇に注意
- 競合条件やレースコンディション
- 新たな事例や発見があれば rcrowleyへ連絡推奨
まとめ
- カーネルのアトミック操作を最大限活用 し、 安全かつ効率的な排他制御 を実現
- ファイルシステムやメモリ操作を適切に選択 し、 ロックレス設計 を推進
- 分散FSや実装差異(例:Mac OS X)には要注意