blog

Linuxシステムは、プロセス間通信に注意する

縦線「|」はパイプラインです。前のコマンドの出力を受け取り、次のコマンドの入力として使います。このパイプの名前からわかるように、パイプは一方通行のデータ転送メカニズムで、実際にはキャッシュの一部分です...

Apr 8, 2020 · 6 min. read
シェア

概要

パイプラインモデル

ps -ef | grep キーワード | awk '{print $2}' | xargs kill -9

ここでの縦線「|」はパイプです。前のコマンドの出力を受け取り、次のコマンドの入力として使用します。パイプの名前からわかるように、パイプは一方通行のデータ転送メカニズムで、実際にはキャッシュであり、中のデータは一方の端から書き込まれ、もう一方の端から読み込まれるだけです。お互いに通信したい場合は、そのために2つのパイプを作成する必要があります。

もう1つのタイプは名前付きパイプです。このタイプのパイプは、mkfifoコマンドで明示的に作成する必要があります。

mkfifo hello

hello はパイプの名前です。パイプはファイルとして存在します。これはLinuxの原則である「すべてがファイルである」ということと一致しています。この時点でlsすると、ファイルタイプがp、つまりパイプであることがわかります。

# ls -l
prw-r--r-- 1 root root 0 May 21 23:29 hello

次に、パイプの中に何かを書くことができます。例えば、文字列を書いてみましょう。

# echo "hello world" > hello

この時、パイプラインの内容は読み出されないので、このコマンドはここで停止されます。これは、あるプロジェクトチームが出力を他のプロジェクトチームに渡して入力させようとする時、前のプロジェクトチームは、引き継ぎが完了していないと放っておけないことを示しています。

この時点で、ターミナルを再接続する必要があります。ターミナルで、以下のコマンドを使ってパイプの中の内容を読んでください:

# cat < hello 
hello world

一方では、パイプラインの内容が読み出され、ターミナルに出力されていることがわかります。他方では、echoコマンドは正常に終了しています。つまり、引継ぎが完了し、前のプロジェクトチームは任務を終えて解散することができます。

パイプは効率が悪いことがわかります。また、プロセス間で頻繁にデータをやり取りするのにも適していません。

メッセージキューモデル

このモデルは、プロセス間通信のメッセージキューモデルに似ています。あるプロセスから別のプロセスへ情報のストリームを流すパイプとは異なり、メッセージキューは電子メールのようなもので、データはメッセージボディと呼ばれる別々のデータ単位で送信されます。

このメッセージ構造の定義を以下に書きました。タイプやテキストは、メッセージの送り手と受け手が合意していれば、必須ではありません。

struct msg_buffer {
 long mtype;
 char mtext;
};

次に、msgget 関数を使用してメッセージ・キューを作成します。この関数は key という引数を取ります。この key はメッセージ・ キューの一意な識別子で、一意でなければなりません。一意でなければなりません。これはやはりファイルに関連付けられています。

ファイルを指定すると、ftokは、そのファイルがメッセージキューの有効期間中に削除されない限り、そのファイルのinodeに基づいてほぼ一意なキーを生成します。ファイルが削除されない限り、ftokが再度呼び出されるたびに同じキーを取得します。これはSystem V IPCのプロセス間通信メカニズムの一部であるため、この章で頻繁に使用されます。

共有メモリモデル

しかし、時にはプロセス間の通信を特に密にし、比較的大きなデータを共有する必要があります。メールを使っていると、一方ではメールがタイムリーに行き来しない、他方では添付ファイルのサイズも制限されている、ということがわかりますので、このようなときには、共有メモリという方法をとることが多いのです。

メモリ管理というと、各プロセスはそれぞれ独立した仮想メモリ空間を持っており、異なるプロセスの仮想メモリ空間は異なる物理メモリにマッピングされていることが知られています。このプロセスがアドレスAにアクセスし、別のプロセスがアドレスAにアクセスする場合、実際には異なる物理メモリアドレスにアクセスしており、データの追加、削除、チェック、変更は互いに影響しません。

しかし、これを回避して、仮想アドレス空間の一部を取り出し、同じ物理メモリにマッピングすることはできませんか。こうすれば、このプロセスが書き込んだものを、他のプロセスがすぐに見ることができ、コピーやコピー、受け渡しをする必要がなくなります。

共有メモリはSystem V IPCのプロセス間通信メカニズムの一部でもあるので、その使い方には見慣れた顔があります。

このシステムでは、IPC オブジェクトの作成はすべて xxxget で行います。 第 1 引数は key で、msgget 内の key と同様、共有メモリ・オブジェクトを一意に特定し ます。第 2 引数は共有メモリのサイズです。第 3 引数は IPC_CREAT です。

int shmget(key_t key, size_t size, int flag);

信号

2つのプロセスが同じ共有メモリにアタッチし、全員が書き込みを行うと、競合が発生する可能性が高くなります。例えば、両方のプロセスが同じアドレスに同時に書き込んだ場合、先に書き込んだプロセスは、その内容が他の誰かによって上書きされていることに気づくでしょう。

そのため、同じ共有リソースに一度に1つのプロセスしかアクセスできないような保護メカニズムが必要になります。System VのIPCプロセス間通信メカニズム・システムでは、これに対する対応はシグナルとして長い間考えられてきました。そのため、シグナルと共有メモリは併用されることが多いです。

セマフォは実際には、プロセス間の通信データを格納するためではなく、プロセス間の相互排除と同期を可能にするために主に使用されるカウンタです。

セマフォは、あるリソースの全体量を表す数値に初期化することができます。セマフォには2つのアトミック操作が定義されており、1つはP操作で、これは要求リソース操作と呼ばれます。この操作はセマフォの値からNを引くことを要求し、その量が要求され、他の誰にも使用できないことを示します。これは、量がセマフォに戻され、他の人が使用できることを示します。

例えば、100ドルを持っている場合、セマフォを100にして、Aが80ドルを借りて、P操作を呼んで80ドルを引くことができます。 同時にBが50ドルを借りてきた場合、BのP操作はAのP操作より後なので、どうしようもなく、Aがお金を返すまで待って、BのP操作が成功することになります。その後、AがVに$30を申請する、つまり$30をあなたに返すために電話をかけると、今度は信号量に$50があるので、BのP操作が成功し、$50を借りることができます。

いわゆる原子操作は、つまり、任意のドルは、P操作を介して一人に貸すことができる、同時に二人に貸すことはできません。つまり、AのP操作とBのP操作は、ほぼ同時に、我々はすべてのアカウントの100が成功している参照してくださいので、することはできませんが、先着順に分割する必要があります。

信号

上述したプロセス間通信の方法は、いずれも通常の状態での作業モードであり、普段の仕事の引き継ぎやメールの送受信、共同開発などに対応するものです。

例えば、オンラインシステムに障害が発生した場合、この時間では、どのような処理にも間に合わず、メールも送れず、会議にも間に合わず、設計者、開発者、運用、保守の全てに通知して、緊急に出動しなければなりません。したがって、システムの7回24時間ノンストップの実行は、アラートシステムを持っている必要があります、一度何かが起こる、人に通知するために、夜中でも、電話呼び出し、障害に対処するために。

オペレーティング・システムでは、シグナルは信号です。シグナルは複雑なデータ構造を持っているわけではなく、コードネームを持つ単なる数字です。Linuxは数十のシグナルを提供し、それぞれが異なる意味を持ちます。シグナルはその値によって互いに区別されます。ちょうど、警察の映画を見ているときに、緊急のアクションに対して、「オペレーション1」が進行中で、警察が動いている、というような感じです。緊急事態ですから、もうブツブツ言ってもしょうがない。

シグナルはいつでもプロセスに送ることができ、プロセスはそのシグナルに対応するシグナル・ハンドラ関数を設定する必要があります。シグナルが発生すると、この関数のデフォルトの実行ができます。これは、システムの緊急マニュアルの私たちの運用と保守に相当し、どのような状況に遭遇したときに、どのようなことを行うには、事前に準備されている、物事のうち、それを行うによると。

Read next

関数の拡張

length 属性は、デフォルト値が指定された関数において、デフォルト値のない引数の数のみを返します。つまり、デフォルト値の引数を持つ関数では length は歪んでしまいます。 これは、length属性が、関数が引数の数が渡されることを期待していることを意味するからです。パラメータにデフォルト値が指定されている場合、期待される引数の数にはそのパラメータは含まれません。 デフォルト値が設定されているパラメータが末尾のパラメータでない場合、...

Apr 8, 2020 · 4 min read