GNU/Linux >> Linux の 問題 >  >> Linux

mmap、msync、および Linux プロセスの終了

あなたの質問に対する正確な回答が見つからなかったので、もう 1 つ追加することにしました:

<オール>
  • まず、データの損失について説明します。書き込みまたは mmap/memcpy メカニズムを使用すると、ページ キャッシュに書き込まれ、ページ置換設定/アルゴリズムに基づいて OS によってバックグラウンドで基盤となるストレージに同期されます。たとえば、Linux には vm.dirty_writeback_centisecs があり、どのページが「古い」と見なされてディスクにフラッシュされるかを決定します。書き込み呼び出しが成功した後にプロセスが停止した場合でも、データはカーネル ページに既に存在し、最終的にストレージに書き込まれるため、データが失われることはありません。データが失われる唯一のケースは、OS 自体がクラッシュした場合 (カーネル パニック、電源オフなど) です。データがストレージに到達したことを確実に確認する方法は、場合によっては fsync または msync (mmap 領域の場合) を呼び出すことです。
  • システム負荷の問題については、リクエストごとに msync/fsync を呼び出すと、スループットが大幅に低下するため、必要な場合にのみ実行してください。 OS のクラッシュでデータが失われるのを防いでいることを忘れないでください。実行される一般的な最適化の 1 つは、適切なバランスを得るために 1 秒などの定期的な間隔で同期を発行することです。

  • この質問に答える Linus Torvalds のコメントを見つけましたhttp://www.realworldtech.com/forum/?threadid=113923&curpostid=114068

    マップされたページはファイルシステム キャッシュの一部です。つまり、そのページに変更を加えたユーザー プロセスが停止した場合でも、そのページは引き続きカーネルによって管理され、そのファイルへのすべての同時アクセスはカーネルを介して行われます。プロセスはそのキャッシュから提供されます。一部の古い Linux カーネルでは異なっていました。それが、一部のカーネル ドキュメントがまだ msync を強制するように指示している理由です。 .

    編集:ありがとう、RobH がリンクを修正しました。

    編集:

    Linux 4.15 以降、コヒーレンスを保証できる新しいフラグ MAP_SYNC が導入されました。

    <ブロック引用>

    このフラグを使用した共有ファイル マッピングは、一部のメモリがプロセスのアドレス空間に書き込み可能にマップされている間、システムがクラッシュまたは再起動された後でも、同じオフセットで同じファイルに表示されることを保証します。

    参照:

    http://man7.org/linux/man-pages/man2/mmap.2.html ページで MAP_SYNC を検索

    https://lwn.net/Articles/731706/


    少し怠惰にならないように、データが確実にディスクに書き込まれるかどうかという質問には、コードを書くことで答えることにしました。答えは書かれるということです。

    以下は、mmap されたファイルにデータを書き込んだ後、突然自分自身を強制終了するプログラムです:

    #include <stdint.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    typedef struct {
      char data[100];
      uint16_t count;
    } state_data;
    
    const char *test_data = "test";
    
    int main(int argc, const char *argv[]) {
      int fd = open("test.mm", O_RDWR|O_CREAT|O_TRUNC, (mode_t)0700);
      if (fd < 0) {
        perror("Unable to open file 'test.mm'");
        exit(1);
      }
      size_t data_length = sizeof(state_data);
      if (ftruncate(fd, data_length) < 0) {
        perror("Unable to truncate file 'test.mm'");
        exit(1);
      }
      state_data *data = (state_data *)mmap(NULL, data_length, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, fd, 0);
      if (MAP_FAILED == data) {
        perror("Unable to mmap file 'test.mm'");
        close(fd);
        exit(1);
      }
      memset(data, 0, data_length);
      for (data->count = 0; data->count < 5; ++data->count) {
        data->data[data->count] = test_data[data->count];
      }
      kill(getpid(), 9);
    }
    

    次のプログラムは、前のプログラムが終了した後に結果のファイルを検証します:

    #include <stdint.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <assert.h>
    
    typedef struct {
      char data[100];
      uint16_t count;
    } state_data;
    
    const char *test_data = "test";
    
    int main(int argc, const char *argv[]) {
      int fd = open("test.mm", O_RDONLY);
      if (fd < 0) {
        perror("Unable to open file 'test.mm'");
        exit(1);
      }
      size_t data_length = sizeof(state_data);
      state_data *data = (state_data *)mmap(NULL, data_length, PROT_READ, MAP_SHARED|MAP_POPULATE, fd, 0);
      if (MAP_FAILED == data) {
        perror("Unable to mmap file 'test.mm'");
        close(fd);
        exit(1);
      }
      assert(5 == data->count);
      unsigned index;
      for (index = 0; index < 4; ++index) {
        assert(test_data[index] == data->data[index]);
      }
      printf("Validated\n");
    }
    

    混乱を招くものを見つけました:

    <ブロック引用>

    munmap はマップされたオブジェクトに影響を与えません。つまり、munmap を呼び出しても、マップされた領域の内容がディスク ファイルに書き込まれません。 . MAP_SHARED 領域のディスク ファイルの更新は、カーネルの仮想メモリ アルゴリズムによって、メモリ マップ領域に格納する際に自動的に行われます。

    これは UNIX® 環境での高度なプログラミング からの抜粋です .

    Linux マンページから:

    <ブロック引用>

    MAP_SHARED このマッピングを、このオブジェクトをマップする他のすべてのプロセスと共有します。リージョンへの保存は、ファイルへの書き込みと同じです。 msync(2) または munmap(2) が呼び出されるまで、ファイルは実際には更新されない場合があります。

    2つは矛盾しているようです。 APUE は間違っていますか?


    Linux
    1. Linuxでゾンビプロセスを見つけて殺す方法

    2. UNIX プロセスの概要 (Linux プロセスの内部とプロセスの種類)

    3. Linuxで単一プロセスのCPU使用率とメモリ使用率を取得しますか?

    1. Linuxコマンドをバックグラウンドで起動し、ターミナルでプロセスをデタッチする方法

    2. Linux:所有されていないプロセスを表示して強制終了する

    3. Ubuntu Linux:プロセス スワップ メモリとメモリ使用量

    1. Linux:ゾンビ プロセスを見つけて強制終了する

    2. linux/if.h と net/if.h の何が問題になっていますか?

    3. Linux で LD_PRELOAD と LD_LIBRARY_PATH をブロックする方法はありますか?