pipeを使用してプログラム本文で信号をキャプチャして処理する
前回の論文では,信号処理関数ではなくプログラムの本文で信号をキャプチャして処理する方法を検討した.当時使われていた案は
本当に安全な方法は、プロセス/スレッド間通信手段を用いて、信号処理関数で信号を外部に送信し、プログラム本文でこれらのデータを傍受することである(
これはグローバル変数を使用する必要があります.私はまだグローバル変数を使用しないスキームはありません.
本住所:https://segmentfault.com/a/1190000009280819
Reference & Related
「UNIX環境高度プログラミング」libeventソース深さプロファイリングsigprocmaskとsigpendingを使用してプログラム本文で信号をキャプチャし、処理する
きほんげんり
キャプチャ信号が設定される前に(
これは、実は「libeventソースコード深さプロファイル」でいうlibeventが
この機能を実現する上で最も重要な
メリット通信チャネルは基本的にFIFOであるため、信号が複数回生成されると、プログラム本文もキューから送られてきたデータを受け取ることができ、複数の信号を逃すことを避けることができる. 信号処理関数は非常に短く、 大量のデータ処理はプログラム本文に置かれ、信号を取得する方法は簡単で、 pipeは、
pipeを選択した理由
「libeventソース深さプロファイリング」においてlibeventは pipe単純 の初期化と作成 pipeの作成は非ネーミングであり、生存サイクルはプロセス内部のみであり、複数のプロセスが同じアーキテクチャを使用することもなく、ネーミング競合の問題が発生する AF_UNIXは名前付きであり、プロトコルスタックが複雑であり、システムオーバーヘッドがやや大きい 一般的に
コード実装
私は自分でepollベースの非同期I/Oライブラリ(GitHubリンク)を設計しています.現在、libeventのような一般的なeventとevsignalが実現されています.この実装に興味があれば、私のプロジェクトに直接コードを見ることができます.本文の内容は主にepEventSignal.cファイルの中の実現である.
主なのは実際には呼び出し を作成する. nonblock、closeonexecオプション を設定は、 に割り当てる.は、 に書き込む.は、 をキャプチャする.
私は自分の簡単なテストプログラムtest_server.cでは、
何か問題があったら教えてください~~~~
sigprocmask()
でした.しかし、その方法は理論的にいくつかの信号を漏らす可能性がある.本当に安全な方法は、プロセス/スレッド間通信手段を用いて、信号処理関数で信号を外部に送信し、プログラム本文でこれらのデータを傍受することである(
epoll
、select
など).これはグローバル変数を使用する必要があります.私はまだグローバル変数を使用しないスキームはありません.
本住所:https://segmentfault.com/a/1190000009280819
Reference & Related
「UNIX環境高度プログラミング」libeventソース深さプロファイリングsigprocmaskとsigpendingを使用してプログラム本文で信号をキャプチャし、処理する
きほんげんり
キャプチャ信号が設定される前に(
signal()
)、まず通信チャネルが作成される.割り込み処理関数では、取得した信号数をこのチャネルに書き込む.一方,プログラム本文では,このチャネルを読み出し,プログラム本文で信号をキャプチャすることができる.これは、実は「libeventソースコード深さプロファイル」でいうlibeventが
evsignal
を実現する案を参考にしたものです.信号処理関数では,printf
などのstdioライブラリの関数を呼び出さないのが一般的であることはよく知られている.理由は「UNIX環境高度プログラミング」の「信号」章の「再入力可能関数」の節を参照してください.この機能を実現する上で最も重要な
read / write
関数は、信号処理関数で呼び出すことができます!これが本案の原理的基礎である.メリット
write()
を呼び出し、極めて少ないデータを書き込むだけでよい.read()
にすぎない.また、取得毎のデータ長は一定である:signum
のタイプはint
であり、sizeof(int)
バイトのデータを取得すればよい.read / write
APIを直接使用して操作することができ、非同期I/Oライブラリを容易にドッキングすることができる.pipeを選択した理由
「libeventソース深さプロファイリング」においてlibeventは
UNIX socket
(AF_UNIX)を使用していると記載されている.ここで私はこの案を使わずにpipeを使いました.理由は以下の通りです.pipe
は親子プロセス間の通信に用いられ、「UNIX環境高度プログラミング」の原文では「単一プロセスのパイプはほとんど役に立たない」とも述べている.私はハハハと笑った--本稿の応用シーンでは、実際にはpipeが数少ない単一プロセス内で使用されている.コード実装
私は自分でepollベースの非同期I/Oライブラリ(GitHubリンク)を設計しています.現在、libeventのような一般的なeventとevsignalが実現されています.この実装に興味があれば、私のプロジェクトに直接コードを見ることができます.本文の内容は主にepEventSignal.cファイルの中の実現である.
主なのは実際には
epEventSignal_AddToBase()
関数です.この関数の操作フローは次のとおりです.pipe()
パイプpipe[0]
をグローバル変数sigaction()
関数を使用して信号をキャプチャする.信号処理関数では、信号値をpipe[0]
pipe[1]
をepoll
に登録する、読み出しイベント私は自分の簡単なテストプログラムtest_server.cでは、
SIGQUIT
(無視、出力のみ)とSIGINT
(event loopの安全な終了をトリガー)の2つの信号がキャプチャされている.読者はチェックアウトしてみてください.何か問題があったら教えてください~~~~