C言語

【C言語】第7章第11回:ファイルロックの基本

ファイルロックは、複数のプログラムが同じファイルに同時アクセスすることを防ぐための重要な技術です。本記事では、C言語でのファイルロックの基本的な概念と実践方法について学びます。

0. 記事の概要

この記事を読むメリット

  • 安全なファイル操作:同時アクセスによるデータ破損を防ぐ技術を学べます。
  • 実践的なスキル:プロジェクトでの信頼性の高いファイル操作を実現できます。
  • 応用力の向上:複雑なファイル操作の要件に対応できるようになります。

この記事で学べること

  • ファイルロックの基本概念
  • C言語でのファイルロックの実装方法
  • 実用的なプログラム例とエラー処理

活用のイメージ

ファイルロックは、ログファイルの安全な更新やデータベースの同時アクセス制御に役立つスキルです。

1. ファイルロックの基本

1.1 ファイルロックとは?

ファイルロックとは、複数のプログラムが同じファイルを同時に操作する際の競合を防ぐための仕組みです。C言語では、POSIX標準のfcntlを使用してファイルロックを実装します。

1.2 fcntlの基本

fcntlは、ファイルのロックやその他の制御操作を実行する関数です。以下は基本的な構文です。

#include <fcntl.h>

int fcntl(int fd, int cmd, struct flock *lock);

パラメータ:

  • fd:ファイルディスクリプタ
  • cmd:操作(例:F_SETLK, F_GETLK
  • lock:ロックの詳細を指定する構造体

1.3 struct flockの構造

struct flockは、ロックの範囲や種類を指定します。

struct flock {
    short l_type;    // ロックの種類(F_RDLCK, F_WRLCK, F_UNLCK)
    short l_whence;  // 基準位置(SEEK_SET, SEEK_CUR, SEEK_END)
    off_t l_start;   // ロックの開始位置
    off_t l_len;     // ロックの長さ
    pid_t l_pid;     // ロックを保持するプロセスのID
};

2. ファイルロックの実装例

2.1 書き込みロックの実装

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    int fd = open("example.txt", O_WRONLY | O_CREAT, 0644);
    if (fd == -1) {
        perror("Error opening file");
        return 1;
    }

    struct flock lock;
    lock.l_type = F_WRLCK;   // 書き込みロック
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;          // ファイル全体をロック

    if (fcntl(fd, F_SETLK, &lock) == -1) {
        perror("Error locking file");
        close(fd);
        return 1;
    }

    printf("File locked successfully. Press Enter to unlock.\n");
    getchar();

    lock.l_type = F_UNLCK;   // ロック解除
    if (fcntl(fd, F_SETLK, &lock) == -1) {
        perror("Error unlocking file");
    }

    close(fd);
    return 0;
}
動作解説
  1. ファイルのオープン:open()でファイルを開きます。
  2. ロックの設定:fcntl()を使用して書き込みロックを設定します。
  3. ユーザー操作:Enterキーを押すとロックを解除します。
  4. ロックの解除:F_UNLCKを使用してロックを解除します。

2.2 読み取りロックの実装

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    int fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
        perror("Error opening file");
        return 1;
    }

    struct flock lock;
    lock.l_type = F_RDLCK;   // 読み取りロック
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;          // ファイル全体をロック

    if (fcntl(fd, F_SETLK, &lock) == -1) {
        perror("Error locking file");
        close(fd);
        return 1;
    }

    printf("File read-locked successfully. Press Enter to release lock.\n");
    getchar();

    lock.l_type = F_UNLCK;   // ロック解除
    if (fcntl(fd, F_SETLK, &lock) == -1) {
        perror("Error unlocking file");
    }

    close(fd);
    return 0;
}
ポイント
  • F_RDLCKを使用して、ファイルに読み取り専用ロックを設定
  • 複数のプロセスが同時に読み取れる

3. 練習問題

以下の課題に挑戦して、ファイルロック操作のスキルを向上させましょう。

  1. 複数のプロセスが同じファイルに同時にアクセスしようとするプログラムを作成し、ファイルロックで競合を防いでください。
  2. ファイルの一部にロックを設定し、特定のデータを安全に操作するプログラムを作成してください。
  3. ロックが設定されているファイルをチェックし、ロックを保持するプロセスのPIDを表示するプログラムを作成してください。

4. 練習問題の解答と解説

問1の解答

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    int fd = open("shared.txt", O_WRONLY | O_CREAT, 0644);
    if (fd == -1) {
        perror("Error opening file");
        return 1;
    }

    struct flock lock;
    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;

    if (fcntl(fd, F_SETLK, &lock) == -1) {
        perror("Error locking file");
        close(fd);
        return 1;
    }

    printf("File is locked. Press Enter to unlock.\n");
    getchar();

    lock.l_type = F_UNLCK;
    if (fcntl(fd, F_SETLK, &lock) == -1) {
        perror("Error unlocking file");
    }

    close(fd);
    return 0;
}

このプログラムでは、ファイルロックを使用して複数プロセスの競合を防ぎます。

5. まとめ

ファイルロックを活用することで、安全で信頼性の高いファイル操作が可能になります。本記事では、基本的なファイルロックの概念と実装方法について学びました。次回は、より高度なロックの使用方法について解説します。