簡単な説明:Linuxプロセス間通信パイプ

Linuxプロセス間の通信チャネルに関する小さなメモ

1.名前のないパイプ

パイプは基本的なプロセス間通信メカニズムであり、相対的なプロセス間で機能してデータ転送を完了します。パイプは、パイプシステム関数を呼び出すことで作成できます。パイプ関数のプロトタイプは次のとおりです。

    #include <unistd.h>
    int pipe(int pipefd[2]);     
    pipefd[0]:读端
    pipefd[1]:写端
    return: 0 成功   -1 失败

名前のないパイプのいくつかの特徴:

  1. パイプラインは、開いているファイルがユーザープログラムに挿入されているように見え、read(filedes [0])またはwrite(filedes [1])を介してこのファイルに対してデータの読み取りと書き込みを行います。
  2. 本質的に、パイプラインはカーネル空間の固定サイズのバッファーです。読み取り/書き込みパイプラインは、このカーネルバッファーの読み取りと書き込みを行います。
  3. カーネルはリングキューメカニズムを使用して、バッファ(4K)実装でパイプラインを実現します。したがって、パイプラインには単方向のデータフロー特性があります。
  4. パイプはどの種類のファイルシステムにも属していないため、ディスクに書き込まれません。メモリにのみ存在し、カーネルスペースです。
  5. このようにして、パイプが関連するプロセス間でのみ使用できる理由を理解できます。パイプはメモリにのみ格納されるため、パイプによって取得されるパイプは毎回異なり、共通の祖先から継承されたパイプのみが同じです。
  6. 書き込まれたコンテンツは毎回パイプラインバッファの最後に追加され、データは毎回バッファの先頭から読み取られます。
  7. パイプラインの特殊性により、lseek関数を使用してパイプライン内をジャンプすることは不可能です。
  8. パイプラインの性質を理解すると、パイプラインの多くの特性を理解できます。たとえば、
    データを読み取ると、パイプラインに存在せず、繰り返し読み取ることができなくなります。
    これは、パイプラインが循環キューメカニズムであり、データの取得後に存在しないためです。キューは
    半二重通信です
    が、これも循環キューのせいではありませんか?
  9. 遺伝的プロセス間の通信のための導管、特別なファイルとしてのパイプは、子供が親プロセスのオープンファイルプロパティを継承することを完全に具体化します
  10. パイプパイプによって取得される記述子pipefd [0]およびpipefd [1]は、通常のファイル記述子と同じであり、通常のファイル記述子と記述子キューを共有します。
  11. パイプは、クローズシステムの下部にあるIO操作を使用して、1つのポート(リーダー/書き込みエンド)を閉じるか、両方のポートを閉じることができます。
  12. 名前のないパイプはプロセスを続行します。つまり、パイプを開いた最後のプロセスが終了すると、パイプは停止し、存在しなくなります。
  13. パイプライン容量は、PIPE_CAPACITYとPIPE_BUFに分けられます。この2つの違いは、PIPE_BUFがカーネルパイプラインバッファーのサイズを定義することです。この値のサイズはカーネルによって設定され(通常は4K)、PIPE_CAPACITYはパイプラインの最大値を参照します。 、つまり容量は、カーネルメモリ内のバッファです
  14. パイプの容量PIPE_CAPACITYは、パイプ関数を使用してパイプを作成するたびにパイプに書き込むことができる最大バイト数を意味します(このマシンでテストされた65535)
  15. パイプの読み取りと書き込みの特性(読み取りと書き込みの両方の端が開いている):パイプの容量がいっぱいになると、データの書き込みがブロックされます。パイプが空の場合、読み取りがブロックされます。
  16. 読み取り/書き込み端の一方の端が閉じている場合、次の特性があります。
    パイプの書き込み端が閉じてパイプにデータがない、読み取りが0を返す(ファイルの最後まで読み取るかのように)、
    パイプのすべての読み取り端が閉じている、プロセスが異常終了する

パイプライン
パイプライン

以下は、パイプラインのデータ構造の実装の説明です。これにより、突然の認識が得られる場合があります。


Linuxでは、パイプラインの実装は特別なデータ構造を使用しませんが、ファイルシステムのファイル構造とVFSのインデックスノードinodeを使用します。これは、2つのファイル構造が同じ一時VFSインデックスノードを指すことによって実現され、このVFSインデックスノードは物理ページを指します。2つのファイルデータ構造(2つのファイル記述子を表す)がありますが、それらはファイル操作ルーチンのアドレスが異なることを定義します.1つはパイプにデータを書き込むルーチンアドレスであり、もう1つはパイプから読み取られますデータのルーチンアドレス。このように、ユーザープログラムのシステム呼び出しは通常のファイル操作ですが、カーネルはこの抽象的なメカニズムを使用して、パイプラインの特別な操作を実現します。


2.有名なパイプ

よく知られているパイプは、関連のないプロセス間で通信するために使用できる方法です。FIFOファイルとも呼ばれ、ファイル名としてファイルシステムに存在する特殊なタイプのファイルですが、その動作は前述の名前のないパイプに似ています。

既知のパイプを使用するには、最初に既知のパイプファイルを作成する必要があります。次の2つの方法があります。

  1. コマンドで作成:
mkfifo fifo
  1. 関数によって作成されました:
#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);

mkfifo()は、パラメーターpathnameに基づいて特別なFIFOファイルを作成します。ファイルは存在してならず、パラメーターmodeはファイルの許可です(mode%〜umask)

もう1つの注意点は、共有フォルダーにパイプファイルfifoを作成できないことです。

名前付きパイプの読み取りおよび書き込み操作は、名前なしパイプの読み取りおよび書き込み操作と同じです。これらはすべて、システムIOの読み取りおよび書き込み操作(読み取り/書き込み)を使用します。パイプファイルを開くには、システムIOオープン関数:openも使用しますが、そのパラメーターにはいくつかの注意点があります。

int fifo_fd = open("xxx",flags);

フラグのオプションのパラメータは以下のとおりです。
O_RDWR
O_RDONLY
O_WRONLY
O_NONBLOCK

オプションO_NONBLOCKは非ブロッキングを意味します。このオプションを追加すると、オープンコールが非ブロッキングであることを意味します。そのようなオプションがない場合は、オープンコールがブロッキングであることを意味します。

  1. 読み取り専用モード(O_RDONLY)で開かれたFIFOファイルの場合、開いている呼び出しがブロックされている(つまり、2番目のパラメーターがO_RDONLYである)場合、プロセスが書き込み用に同じFIFOを開かない限り、ファイルは返されません。openが呼び出された場合これは非ブロッキングであり(つまり、2番目のパラメーターはO_RDONLY | O_NONBLOCKです)、他のプロセスが書き込みモードで同じFIFOファイルを開かなくても、open呼び出しは成功し、すぐに戻ります。
  2. 書き込み専用モード(O_WRONLY)で開かれたFIFOファイルの場合、開いている呼び出しがブロックされている(つまり、2番目のパラメーターがO_WRONLYである)と、プロセスが同じFIFOファイルを読み取り専用モードで開くまで開いている呼び出しがブロックされます。オープンコールが非ブロッキングの場合(つまり、2番目のパラメータがO_WRONLY | O_NONBLOCKの場合)、openは常にすぐに戻りますが、他のプロセスが同じFIFOファイルを読み取り専用モードで開かない場合、オープンコールは-1を返し、FIFOは開店します。

有名なパイプには他の特徴があります。

  1. 既知のパイプファイルは通常のファイルではありませんが、実際にはカーネル内のバッファーであるため、lseekを使用して既知のパイプファイルを操作することはできません。
  2. パイプラインにデータを書き込んだ後、ls -l fifoを使用してパイプラインファイルを表示すると、パイプラインファイルのサイズが常に0であることがわかります。これは、パイプラインのデータがファイルシステムに表示されないことを意味します。カーネルのバッファを介して交換されますが、名前のないパイプと比較すると、ファイルシステムにもう1つのファイル名が表示されるため、名前の付いたパイプと呼ばれます。

概要:パイプラインを通じて、プロセス間通信を垣間見ることができ、いくつかのプロセス間通信の本質的な特性を知ることができます。

すべてのプロセス間通信はカーネルを介して実行する必要があります。異なるプロセス間の仮想メモリ空​​間は互いに独立しているため、データを交換する場合は、カーネル空間をバイパスする必要があります。特定のプロセスは、最初にデータをカーネル空間に配置し、次にデータを配置します。次に、他のプロセスがカーネル空間からデータを取得します。


参照:

  1. https://blog.csdn.net/qq_42914528/article/details/82023408
  2. https://blog.csdn.net/rannianzhixia/article/details/72793895
  3. 「UNIXアドバンストプログラミング」

おすすめ

転載: blog.csdn.net/weixin_41629848/article/details/97523339