16

Linux固有かどうかに関係なく、shm_open()プロセスが使用していないときにposix共有メモリセグメント(で取得)を削除する方法はありますか?つまり、それらを参照カウントし、参照が0になったときにシステムにそれらを削除させます

いくつかの注意:

  • プログラムがクラッシュした場合、それらを削除するためのatexitハンドラーの確立は機能しません。

  • 現在、Linux固有の方法で、セグメント名にpidを埋め込み、外部プログラムで/ dev / shmをウォークして、未使用のセグメントを見つけようとしています。これには、かなりハック的な方法で外部から定期的にクリーンアップする必要があるという欠点があります。

  • プログラムは複数のコピーを実行できるため、プログラムの起動時にプログラムが再利用するセグメントに明確に定義された名前を使用することはできません。

4

7 に答える 7

7

共有メモリセグメントを開く必要があるすべてのプロセスがすでに開いていることがよく知られているときにプログラムの実行にポイントがある場合は、安全にリンクを解除できます。リンクを解除すると、オブジェクトはグローバル名前空間から削除されますが、ファイル記述子を開いたままにするプロセスが少なくとも1つある限り、オブジェクトは残ります。それ以降にクラッシュが発生した場合、ファイル記述子は自動的に閉じられ、参照カウントがデクリメントされます。リンクされていない共有メモリブロックへの開いている記述子がなくなると、削除されます。

これは、次のシナリオで役立ちます。プロセスが共有メモリブロックを作成し、リンクを解除してからフォークします。子はファイル記述子を継承し、共有メモリブロックを使用して親と通信できます。両方のプロセスが終了すると、両方のファイル記述子が閉じられるため、ブロックは自動的に削除されます。

リンクが解除されている間、共有メモリブロックは他のプロセスが開くことができません。一方、shm_open()リンクされていないブロックと同じ名前で使用すると、代わりに、まったく異なる新しい共有メモリブロックが作成されます。

于 2012-11-18T22:17:10.547 に答える
5

いいえ-少なくともLinuxでは、カーネルにはこれを実行できるものは何も含まれていません。共有メモリセグメントを取り除くために、ある時点でshm_unlink()を呼び出すのは、アプリケーション次第です。

于 2012-11-14T17:25:21.610 に答える
4

システムコマンドとLinuxコマンド「fuser」を使用して、ファイルを開いたプロセスを一覧表示する方法を見つけました。このようにして、共有メモリファイル(/ dev / shm "にあります)がまだ使用されているかどうかを確認し、使用されていない場合は削除できます。チェック/削除/作成の操作は、プロセス間のクリティカルセクションで囲む必要があることに注意してください。名前付きミューテックスまたは名前付きセマフォまたはファイルロックを使用します。

        std::string shm_file = "/dev/shm/" + service_name + "Shm";
        std::string cmd_line = "if [ -f " + shm_file + " ] ; then if ! fuser -s " + shm_file + " ; then rm -f " + shm_file + " ; else exit 2 ; fi else exit 3 ; fi";
        int res = system(cmd_line.c_str());
        switch (WEXITSTATUS(res)) {
        case 0: _logger.warning ("The shared memory file " + shm_file + " was found orphan and is deleted");         break;
        case 1: _logger.critical("The shared memory file " + shm_file + " was found orphan and cannot be deleted");  break;
        case 2: _logger.trace   ("The shared memory file " + shm_file + " is linked to alive processes");            break;
        case 3: _logger.trace   ("The shared memory file " + shm_file + " is not found");                            break;
        }
于 2013-05-12T13:53:34.100 に答える
3

sysV APIを使用して作成された共有メモリの場合、このような動作をすることができます。Linuxのみ。これはPOSIX共有メモリではありませんが、機能する可能性があります。

本の中で、shmctl()の可能なパラメータの1つであるLinuxプログラミングインターフェイスは、次のように説明されています。

IPC_RMID共有メモリセグメントとそれに関連するshmid_dsデータ構造を削除対象としてマークします。現在セグメントがアタッチされているプロセスがない場合、削除はすぐに行われます。それ以外の場合、セグメントは、すべてのプロセスがセグメントから切り離された後(つまり、shmid_dsデータ構造のshm_nattchフィールドの値が0に下がったときに)削除されます。一部のアプリケーションでは、すべてのプロセスがshmat()を使用して共有メモリセグメントを仮想アドレス空間にアタッチした直後に削除のマークを付けることで、アプリケーションの終了時に共有メモリセグメントが適切にクリアされるようにすることができます。これは、ファイルを開いた後でファイルのリンクを解除することに似ています。Linuxで、共有セグメントがIPC_RMIDを使用して削除対象としてマークされているが、一部のプロセスにまだ接続されているためにまだ削除されていない場合、その後、別のプロセスがそのセグメントをアタッチすることが可能です。ただし、この動作は移植性がありません。ほとんどのUNIX実装では、削除対象としてマークされたセグメントへの新しい接続が防止されます。(SUSv3は、このシナリオでどのような動作が発生するかについては沈黙しています。)いくつかのLinuxアプリケーションがこの動作に依存するようになりました。そのため、Linuxは他のUNIX実装と一致するように変更されていません。

于 2016-02-18T15:06:38.407 に答える
3

最も複雑なケースを想定しましょう。

  • 共有メモリを介して通信するいくつかのプロセスがあります
  • それらはいつでも、複数回でも開始および終了できます。つまり、マスタープロセスも、共有メモリを初期化できる専用の「最初の」プロセスもありません。
  • つまり、たとえば、共有メモリのリンクを安全に解除できるポイントがないため、SergeyとHristoのどちらの回答も機能しません。

私は2つの可能な解決策を見つけ、インターネットがこの質問についてひどく沈黙しているので、それらについてのフィードバックを歓迎します。

  1. 共有メモリ内の共有メモリにロックとして書き込んだ最後のプロセスのpid(または、より具体的なプロセス識別子がある場合はそれ)を格納します。その後、sthを行うことができます。次の擬似コードのように:

     int* pshmem = open shared memory()
    
     while(true) 
         nPid = atomic_read(pshmem)
         if nPid = 0 
            // your shared memory is in a valid state
            break
         else 
            // process nPid holds a lock to your shared memory
            // or it might have crashed while holding the lock
            if process nPid still exists 
              // shared memory is valid
              break
            else 
              // shared memory is corrupt
              // try acquire lock 
              if atomic_compare_exchange(pshmem, nPid, my pid) 
                 // we have the lock
                 reinitialize shared memory
                 atomic_write(pshem, 0) // release lock
              else 
                 // somebody else got the lock in the meantime
                 // continue loop
    

    これは、最後のライターが書き込み中に死亡しなかったことを確認します。共有メモリは、どのプロセスよりも長く持続します。

  2. リーダー/ライターファイルロックを使用して、共有メモリオブジェクトを開く最初のプロセスがプロセスであるかどうかを確認します。次に、最初のプロセスで共有メモリを再初期化できます。

     // try to get exclusive lock on lockfile
     int fd = open(lockfile, O_RDONLY | O_CREAT | O_EXLOCK | O_NONBLOCK, ...)
     if fd == -1
         // didn't work, somebody else has it and is initializing shared memory
         // acquire shared lock and wait for it
         fd = open(lockfile, O_RDONLY | O_SHLOCK)
         // open shared memory
     else 
         // we are the first
         // delete shared memory object
         // possibly delete named mutex/semaphore as well
    
         // create shared memory object (& semaphore)
         // degrade exclusive lock to a shared lock
         flock(fd, LOCK_SH)
    

    ファイルロックは、プロセスが終了したときに自動的にクリアされるPOSIXシステム上の唯一の(?)メカニズムのようです。残念ながら、それらを使用するための警告のリストは非常に長いです。アルゴリズムはflock、少なくともローカルマシンの基盤となるファイルシステムでサポートされていることを前提としています。アルゴリズムは、ロックがNFSファイルシステム上の他のプロセスに実際に表示されているかどうかを気にしません。それらは、共有メモリオブジェクトにアクセスするすべてのプロセスに対してのみ表示される必要があります。

    このソリューションは、boost.interprocessの上に実装されています。

于 2016-09-23T11:37:29.230 に答える
0

カウントを参照するためにグローバルカウントセマフォを使用するだけではありませんか?アタッチとデタッチの呼び出しをラップして、メモリにアタッチするときにセマフォがインクリメントされ、デタッチするときにデクリメントされるようにします。デタッチによってセマフォがゼロになったら、セグメントを解放します。

于 2012-11-14T12:05:51.573 に答える
0

以下が機能するかどうか、または実行可能かどうかはわかりません。しかし、私の試み。

プログラムがクラッシュするたびに実行されるヘルパープログラムを実行してみませんか。

すなわち:

/proc/sys/kernel/core_pattern  to  /path/to/Myprogram %p

Myprogramは、プロセスがクラッシュしたときに実行されます。おそらく、さらに詳しく調べることができます。

見る

man 5 core.  for more information. 

これがある程度役立つことを願っています。

于 2012-11-14T12:37:18.360 に答える