問題タブ [shared-memory]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - 異なるプロセスで共有されるリング バッファを作成するのが (C++ で) 難しいのはなぜですか?
私はこれについて特に密集していますが、私がやりたいことは共通でなければならないので、重要で基本的なポイントか何かが欠けているようです:
マネージャー プロセス ( ) から固定サイズのリング バッファー オブジェクトを作成する必要がありますProcess M
。このオブジェクトには、バッファから読み書きするメソッドがwrite()
あります。read()
読み取り/書き込みメソッドは、独立したプロセス (Process R
およびW
)によって呼び出されます。
バッファを実装しました。これはSharedBuffer<T&>
、boost::interprocess を使用して SHM にバッファ スロットを割り当て、単一のプロセス内で完全に動作します。SO でこの質問とその質問への回答を読み、自分自身に尋ねましたが、異なるプロセスが共通のオブジェクトからメソッドにアクセスする方法についてはまだわかりません。Boost doc には、 SHM でベクトルを作成する例があり、これは私が望むものと非常に似ていますが、独自のクラスをインスタンス化したいと考えています。
私の現在のオプションは次のとおりです。
new
Charles B. が私の質問に提案したように、配置を使用してください。ただし、彼は、POD 以外のオブジェクトを SHM に入れるのは得策ではないと警告しています。しかし、私のクラスには読み取り/書き込みメソッドが必要です。どうすればそれらを処理できますか?- クラス定義にアロケータを追加します。たとえば、ブーストで指定されたベクトルの例
SharedBuffer<T&, Alloc>
と同様に進めます。これは本当に複雑に聞こえます。 - POD クラスに変更
SharedBuffer
します。つまり、すべてのメソッドを取り除きます。しかし、プロセス間で読み取りと書き込みを同期するにはどうすればよいでしょうか。
私は何が欠けていますか?固定長のリング バッファは非常に一般的であるため、この問題には解決策があるか、何か間違ったことをしている可能性があります。
c++ - 共有メモリ内のカスタム アロケータを使用してクラスをインスタンス化する
次の問題が原因で髪を引っ張っています。boost.interprocess ドキュメントに記載されている例に従って、共有メモリに記述した固定サイズのリング バッファー バッファー クラスをインスタンス化しています。私のクラスのスケルトン コンストラクターは次のとおりです。
私の最初の質問: この種の割り当ては、バッファ ノードが連続したメモリ ロケーションに割り当てられることを保証しますか?つまりm_start_ptr + n*sizeof(BufferNode)
、Read()
メソッドでアドレスから n 番目のノードにアクセスしようとすると、機能しますか? そうでない場合、リンクされたリストを作成して、ノードを保持するためのより良い方法は何ですか?
私のテストハーネスは次のとおりです。
これにより、最後のステートメントのテンプレートに関連するあらゆる種類のコンパイル エラーが発生します。私は何を間違っていますか?segment.construct<MyBuf>("MyBuffer")(100, alloc_inst)
2 つのテンプレート パラメータを提供する正しい方法はありますか?
c++ - Boost.Interprocessのmanage_shared_memory.construct()にパラメーターを渡す方法
私はBoost.Interprocessのドキュメントを何時間も見つめてきましたが、それでもこれを理解することができませんでした。ドキュメントには、次のように共有メモリにベクターを作成する例があります。
今、私はこれを理解しています。私が立ち往生しているのはsegment.construct()
、要素の数を指定するために2番目のパラメーターを渡す方法です。construct()
プロセス間ドキュメントは、としてのプロトタイプを提供します
でもやってみると
コンパイルエラーが発生します。
私の質問は次のとおりです。
- オブジェクトのコンストラクターである、
par1, par2
からパラメーターを実際に渡されるのは誰ですか。私の理解では、テンプレートアロケータパラメータが渡されています。あれは正しいですか?segment.construct
vector
alloc_inst
共有メモリに作成されているオブジェクトのコンストラクターに必要なパラメーターに加えて、別のパラメーターを追加するにはどうすればよいですか?
これに関する簡潔なBoostドキュメント以外の情報はほとんどありません。
c++ - 共有メモリ内の C++ コンテナー クラスに関する簡単な設計上の質問
IPC の共有メモリ (shm) にリング バッファーを実装するために、boost::interprocess のベクター コンテナーの周りに単純なラッパーを作成しています。がshmで作成されbuf
たインスタンスであるとします。RingBuffer
現在、その ctor で、buf
それ自体が値を格納するためにプライベートboost::interprocess::vector
データ メンバーを割り当てますm_data
。m_data
私の質問は、共有メモリにも作成する必要があると思います。しかし、これは必需品ですか?
それがshm自体で作成され、標準メモリを割り当てた場合buf
、つまりnew
. これは呼び出しプロセスのヒープに割り当てられますか? そこに割り当てられているとは思わないbuf
ので、プロセスのヒープ上にないオブジェクトにプライベートなデータメンバーがそこに割り当てられるのはなぜですか。よくわかりません。
c++ - ページの粒度よりも細かい特定のメモリ位置への書き込みが発生した場合、強制的にクラッシュさせることはできますか?
パフォーマンス上の理由から共有メモリを使用するプログラムを作成しています(代替手段としてのソケットとパイプが評価されており、これらは私のタスクには十分な速度ではありません。一般的に、コピーを含むIPCメソッドは遅すぎます)。共有メモリ領域では、固定サイズの多くの構造体を書いています。構造体を共有メモリに書き込むためのプログラムが1つあり、そこから読み取る多くのクライアントがあります。ただし、クライアントが書き込む必要のある各構造体のメンバーは1つです(参照カウント。アトミックに更新されます)。他のすべてのメンバーは、クライアントに対してのみ読み取る必要があります。
クライアントはその1つのメンバーを変更する必要があるため、共有メモリ領域を読み取り専用としてマップすることはできません。ただし、他のメンバーをいじくり回してはいけません。これらのプログラムはC ++で記述されているため、メモリが破損する可能性があります。理想的には、あるクライアントが別のクライアントをクラッシュさせることは可能な限り困難である必要があります。私はバグのあるクライアントについてのみ心配しており、悪意のあるクライアントについては心配していないので、不完全な解決策は許可されています。
ヘッダーでconstとして使用するメンバーを宣言することで、クライアントによる上書きを阻止することができますが、それでもメモリの破損(バッファオーバーフロー、不正なキャストなど)による上書きを防ぐことはできません。カナリアを挿入することはできますが、それをチェックするための費用を常に支払う必要があります。
参照カウントメンバーを直接保存する代わりに、構造体を読み取り専用のマップされたページに保持しながら、実際のデータへのポインターを別のマップされた書き込み専用ページに保存することができます。これは機能します。ポイントされたデータに書き込もうとすると、OSによってアプリケーションが強制的にクラッシュしますが、ロックフリーアルゴリズムを書き込もうとすると、間接ストレージが望ましくない場合があります。これは、別のレベルの間接参照に従う必要があると、何かができるかどうかが変わる可能性があるためです。アトミックに行われます。
メモリの小さな領域にマークを付けて、それらを書き込むとアプリが爆発するようにする方法はありますか?一部のプラットフォームにはハードウェアウォッチポイントがあり、インラインアセンブリでそれらの1つをアクティブ化できるかもしれませんが、32ビットx86では一度に4つに制限され、それぞれが制限されているため、構造体の一部しかカバーできませんでした4バイトまで。また、プログラムをデバッグするのが面倒になります;)
編集:私はこのかなり目を見張るような紙を見つけましたが、残念ながら、ECCメモリと変更されたLinuxカーネルを使用する必要があります。
multithreading - オフセットを使用せずにポインタを共有メモリに格納することは可能ですか?
共有メモリを使用する場合、各プロセスは、共有領域をそれぞれのアドレス空間の異なる領域にマップすることがあります。これは、共有領域内にポインタを格納する場合、共有領域の開始位置のオフセットとして格納する必要があることを意味します。残念ながら、これはアトミック命令の使用を複雑にします (例えば、ロックフリーのアルゴリズムを書こうとしている場合))。たとえば、単一のライターによって作成された、共有メモリ内に多数の参照カウント ノードがあるとします。ライターは、正の参照カウントを持つ有効なノードを指すように、ポインター 'p' を定期的にアトミックに更新します。リーダーは、最初の要素が参照カウントであるノード (構造体) の先頭を指しているため、「p」にアトミックに書き込みたいと考えています。p は常に有効なノードを指しているため、ref カウントのインクリメントは安全であり、'p' の逆参照や他のメンバーへのアクセスを安全に行うことができます。ただし、これはすべて、すべてが同じアドレス空間にある場合にのみ機能します。ノードと「p」ポインタが共有メモリに格納されている場合、クライアントは競合状態になります。
- x = p を読む
- y = x + オフセット
- y で refcount をインクリメントする
ステップ 2 で、p が変更され、x が有効なノードを指しなくなる場合があります。私が考えることができる唯一の回避策は、オフセットではなく実際のポインターを mmap された領域に格納できるように、すべてのプロセスが共有メモリをマップする場所に同意するよう強制することです。それを行う方法はありますか?mmap のドキュメントに MAP_FIXED がありますが、安全なアドレスを選択する方法がわかりません。
編集: x86 でインライン アセンブリと 'lock' プレフィックスを使用すると、「値 Z によるオフセット Y で ptr X をインクリメントする」ことは可能でしょうか? 他のアーキテクチャの同等のオプション? 多くのアセンブリを書いていません。必要な指示が存在するかどうかわかりません。
sql-server - SQLServer2008に接続できません-共有メモリの問題のようです
SQL ServerManagementStudioを使用してSQLServer2008Expressのローカルインスタンスに接続できません。
この問題は、接続プロトコルに加えた変更に関連していると思います。エラーが発生する前に、共有メモリを有効にし、名前付きパイプとTCP/IPを無効にしました。次に、名前付きパイプとTCP / IPの両方を有効にしました。これが、問題が発生し始めたときです。
SSMSを使用して(SQLサーバーのsysadminログインまたはWindows認証を使用して)サーバーに接続しようとすると、次のエラーメッセージが表示されます。
サーバーとの接続は正常に確立されましたが、ログインプロセス中にエラーが発生しました。(プロバイダー:名前付きパイププロバイダー、エラー:0-パイプのもう一方の端にプロセスがありません。)(Microsoft SQL Server、エラー:233)
名前付きパイプエラーが返されるのはなぜですか?接続プロトコルのリストで優先順位が高いため、共有メモリを使用しないのはなぜですか?なんらかの理由で共有メモリをリッスンしていないようですが?
名前付きパイプを有効に設定して接続しようとすると、同じエラーメッセージが表示されます。
私のWindowsアカウントには、私のコンピューターに管理者権限がありません-おそらくこれは何らかの形で違いを生んでいます( 「SuperSocketNetLib \ Lpc」レジストリキーに関するこの投稿の議論のいくつかが示唆しているようです)。
c++ - あるループが別のループよりも共有メモリの更新を検出するのに時間がかかるのはなぜですか?
共有メモリに書き込む「サーバー」プログラムと、メモリから読み取るクライアント プログラムを作成しました。サーバーには、書き込み可能なさまざまな「チャネル」があります。これは、アイテムを追加しているリンクリストが異なるだけです。クライアントは、リンクされたリストのいくつかに関心があり、それらのリストに追加されたすべてのノードを、可能な限り最小限のレイテンシーで読み取りたいと考えています。
クライアントには2つのアプローチがあります。
リンクされたリストごとに、クライアントは「ブックマーク」ポインタを保持して、リンクされたリスト内の場所を維持します。リンクされたリストをラウンド ロビンし、それらすべてを何度も反復し (永遠にループします)、可能であれば各ブックマークを毎回 1 ノードずつ進めます。それができるかどうかは、ノードの「次の」メンバーの値によって決まります。null 以外の場合、次のノードへのジャンプは安全です (サーバーはそれを null から非 null にアトミックに切り替えます)。このアプローチは問題なく機能しますが、繰り返し処理するリストが多数あり、更新を受け取るリストがごくわずかである場合、レイテンシーが悪化します。
サーバーは、各リストに一意の ID を付与します。サーバーがアイテムをリストに追加するたびに、リストの ID 番号もマスターの「更新リスト」に追加します。クライアントは 1 つのブックマーク (更新リストへのブックマーク) のみを保持します。ブックマークの次のポインタが null でないかどうか ( ) を際限なくチェックし、
while(node->next_ == NULL) {}
そうである場合は先に進み、指定された ID を読み取り、その ID を持つリンク リストの新しいノードを処理します。理論的には、クライアントは毎回すべてのリストを反復処理する必要がないため、多数のリストをより適切に処理できるはずです。
両方のアプローチのレイテンシを (gettimeofday を使用して) ベンチマークしたところ、驚いたことに #2 はひどかった。最初のアプローチは、リンクされたリストの数が少ない場合、多くの場合、20us 未満のレイテンシになります。2 番目のアプローチでは、低レイテンシーの小さなスパッツがありますが、多くの場合、4,000 ~ 7,000us です。
gettimeofday をあちこちに挿入することで、アプローチ 2 で追加されたすべてのレイテンシが、次のポインターが null でないかどうかを繰り返しチェックするループで費やされていることがわかりました。これは私には不可解です。2 番目のアプローチでは、1 つのプロセスでの変更が 2 番目のプロセスに「発行」されるまでに時間がかかっているようです。ある種のキャッシュの相互作用が起こっていると思いますが、私にはわかりません。どうしたの?
更新:もともと、アプローチ#2は条件変数を使用していたため、node->next_ == NULL
条件を待機すると、サーバーは更新を発行するたびに条件を通知しました。レイテンシーは同じで、コードを上記のアプローチにまで減らした理由を理解しようとしました。マルチコア マシンで実行しているため、1 つのプロセスのスピンロックが他のプロセスに影響を与えることはありません。
更新 2: node->next_ は揮発性です。
c++ - 共有メモリからリンクリストを読み取るためのこれらの3つの方法のうち、3番目に速いのはなぜですか?
外部イベントに応答して共有メモリ内の多くのリンクリストを更新する「サーバー」プログラムがあります。クライアントプログラムがリストの更新にできるだけ早く気付くようにしたい(待ち時間が最も短い)。サーバーは、データが入力され、次のポインターが有効な場所に設定されると、リンクリストのノードをマークしstate_
ます。FILLED
それまでstate_
はですNOT_FILLED_YET
。私はメモリバリアを使用して、内部のデータが実際に準備ができている前のようにクライアントに表示state_
されないようにしています(そして、動作しているように見えますが、破損したデータは表示されません)。FILLED
また、state_
コンパイラがクライアントによるループからのチェックを解除しないようにするために、揮発性です。
サーバーコードをまったく同じに保ちながら、クライアントがリンクリストをスキャンして変更を確認するための3つの異なる方法を考え出しました。問題は、なぜ3番目の方法が最速なのかということです。
方法1:すべてのリンクリスト(「チャネル」と呼ばれる)を継続的にラウンドロビンし、ノードが「FILLED」に変更されているかどうかを確認します。
方法1では、チャネル数が少ない場合に遅延が非常に小さくなりました。しかし、チャネル数が増えると(250K以上)、すべてのチャネルをループするため、非常に遅くなりました。だから私は試しました...
方法2:各リンクリストにIDを付けます。別の「更新リスト」を横に置いておきます。リンクリストの1つが更新されるたびに、そのIDを更新リストにプッシュします。ここで、単一の更新リストを監視し、そこから取得したIDを確認する必要があります。
方法2はひどい待ち時間を与えました。方法1では10us未満の遅延が発生する可能性がありますが、方法2では不可解なことに8msの遅延が発生することがよくあります。gettimeofdayを使用すると、update_cursor-> state_の変更が、サーバーのビューからクライアントのビューに伝達するのに非常に時間がかかったようです(私はマルチコアボックスを使用しているため、遅延はキャッシュによるものと思われます)。だから私はハイブリッドアプローチを試しました...
方法3:更新リストを保持します。ただし、すべてのチャネルを継続的にループし、各反復内で更新リストが更新されているかどうかを確認します。ある場合は、番号を押し込んでください。そうでない場合は、現在繰り返しているチャネルを確認してください。
この方法の遅延は方法1と同じくらい良好でしたが、多数のチャネルにスケーリングされました。問題は、理由がわからないことです。物事にレンチを投げるだけです。「更新で見つかりました」の部分のコメントを外すと、すべてのレイテンシログメッセージの間に出力されます。つまり、更新リストでしか見つからないということです。したがって、この方法が方法2よりもどのように高速になるかわかりません。
テストデータとしてランダムな文字列を生成する完全なコンパイル可能なコード(GCCとboost-1.41が必要)は次の場所にあります:http://pastebin.com/0kuzm3Uf
更新:更新が発生するまで、3つの方法すべてが効果的にスピンロックされます。違いは、更新が行われたことに気付くのにかかる時間です。それらはすべて継続的にプロセッサに負担をかけるため、速度の違いを説明することはできません。私は他に何も実行されていない4コアのマシンでテストしているので、サーバーとクライアントは競合するものがありません。更新が条件を通知し、クライアントに条件を待機させるバージョンのコードを作成しました。これは、どのメソッドのレイテンシーにも役立ちませんでした。
Update2:3つの方法がありますが、一度に試したのは1つだけなので、state_メンバーをめぐって競合しているのは1つのサーバーと1つのクライアントだけです。
apache2 - 共有メモリ セグメントに apr_table_t タイプのテーブルを作成するにはどうすればよいですか?
共有メモリ セグメントに apr_table_t タイプのテーブルを作成するにはどうすればよいですか?