C LANGUAGE TECHNOLOGY

【C言語】select/pselect/poll/ppoll/epoll関数の違い

悩んでいる人

C言語のselect/pselect/poll/ppoll/epoll関数の違いを教えて!

こういった悩みにお答えします.

本記事の信頼性

  • リアルタイムシステムの研究歴12年.
  • 東大教員の時に,英語でOSの授業.
  • 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校コンピュータサイエンス学部2021年の世界大学学術ランキングで20位)で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発
  • プログラミング歴15年以上,習得している言語: C/C++Solidity/Vyper,Java,Python,Ruby,HTML/CSS/JS/PHP,MATLAB,Assembler (x64,ARM).
  • 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」GitHubにオープンソースとして公開

こういった私から学べます.

C言語のselect/pselect/poll/ppoll/epoll関数の違いを紹介します.

select/pselect関数

select/pselect関数は,プログラムで複数のファイルディスクリプタを監視し,一つ以上のファイルディスクリプタがある種のI/O操作の「ready(準備ができた)」状態(例:読み込み可能になった状態)になるまで待つことができる関数です.

ここで,ファイルディスクリプタが ready状態とは,read関数等のI/O操作が停止(block)なしに実行したり,write関数を実行したりできる状態にあることを意味します.

select関数とpselect関数の動作は同じですが,以下が異なります.

  • select関数では,タイムアウト時間の指定に構造体struct timeval(秒・マイクロ秒単位)を利用しますが,pselect関数では構造体struct timespec(秒・ナノ秒単位)を利用します.
  • select関数は残り時間を示すtimeout引数を更新することがありますが,pselect関数はこの引数を変更しない.
  • select関数はsigmask引数を持たない.その動作はsigmaskにNULLを指定した場合のpselect関数と同じです.

3つの独立したファイルディスクリプタ集合の監視を行います.

readfdsに入れられたディスクリプタについては,読み込みが可能かどうかを監視します.

より正確にいうと,停止(block)なしで読むことができるかを調べます.

ファイルの終端 (EOF:End-Of-File) の場合も,ファイルディスクリプタは読み込み可能として扱われます.

writefdsに入れられたディスクリプタについては,書き込み用に利用可能な領域があるかを監視します.

ただし,大きな書き込みの場合には停止する可能性はあります.

exceptfdsにあるものについては,例外の監視を行います.

システムコール終了時に,どのファイルディスクリプターの状態が実際に変化したか示すために,集合の内容が変更されます.

ある種別のイベントを監視したいファイルディスクリプタが一つもない場合には,対応するファイルディスクリプタ集合にNULLを指定することができます.

集合を操作するために4つのマクロが提供されています.

FD_ZEROは集合を消去します.

FD_SETとFD_CLRはそれぞれ指定したファイルディスクリプタの集合への追加,削除を行います.

FD_ISSETは集合にファイルディスクリプタがあるかどうか調べます.

fd_setは固定サイズのバッファで,負やFD_SETSIZE(1,024の場合が多い)以上の値を持つfdに対してFD_CLR/FD_SETマクロを実行した場合,未定義に動作になるので注意して下さい.

nfdsは3つの集合に含まれるファイルディスクリプタの最大値に1を足したものです.

timeout引数は,select関数がファイルディスクリプタがready状態になるのを待って停止する時間を指定します.

呼び出しは以下のいずれかになるまで停止します.

  • ファイルディスクリプタが利用可能になった.
  • システムコールがシグナルハンドラにより割り込まれた.
  • タイムアウト時間が満了した.

このtimeout時間はシステムクロックの粒度に切り上げられ,カーネルのスケジューリング遅延により少しだけ長くなる可能性がある点に注意して下さい.

timeval構造体の両方のフィールドが0の場合,select関数はすぐに復帰します.

この機能はポーリング(polling)を行うのに便利です.

timeoutにNULL(タイムアウトなし)が指定されると,select関数は無期限に停止(block)します.

sigmaskは,シグナルマスクへのポインタです.

sigmaskがNULLでない場合,pselect関数はsigmaskが指しているシグナルマスクで現在のシグナルマスクを置き換えてからselect関数を実行し,終了後にシグナルマスクを元のシグナルマスクに戻します.

select関数の使い方

select関数の使い方は以下になります.

実行結果は以下になります.

エンターキーを入力するとデータを取得したことがわかります.FD_ISSETの返り値は1になります.

また,実行後に何もせずに3秒待つとタイムアウトされた旨が表示されます.FD_ISSETの返り値は0になります.

pselect関数の使い方

pselect関数の使い方は以下になります.

実行結果は以下になります.同様です.

poll/ppoll関数

poll/ppoll関数を紹介します.

poll関数はselect関数と同様のタスクを実行します.

つまり,ファイルディスクリプタのセットのうち,I/Oを実行する準備ができたready状態のものを待ちます.

  • fds:監視するファイルディスクリプタ集合
  • nfds:fds配列の要素数を指定
  • timeout:ファイルディスクリプターが利用可能になるまでpoll関数が停止する時間をミリ秒で指定
  • tmo_p:ppoll関数が停止する時間の上限を指定
  • sigmask:シグナルマスクのサイズをバイト数で指定(NULLの場合,poll/ppoll関数の違いはtimeout引数の精度のみ)

fdsは,以下のstruct pollfd構造体の配列です.

  • fd:オープンされたファイルのファイルディスクリプタ
  • events:入力パラメータで,ファイルディスクリプタfd に関して,アプリケーションが興味を持っているイベントのビットマスクを指定
  • revents:出力パラメーターで,実際に起こったイベントがカーネルにより設定

tmo_pには以下のstruct timespec構造体へのポインタを指定します.

tmo_pがNULLの場合,ppoll関数は無限に停止する可能性があります.

poll関数とppoll関数の関係は,select関数とpselect関数の関係と同様です.

pselect関数と同様に,ppoll関数を利用するとアプリケーションはファイルディスクリプタの状態変化やシグナルの捕捉を安全に待つことができます.

poll関数の使い方

poll関数の使い方は以下になります.

実行結果は以下になります.

実行するとPOLLOUTの表示のみがでます.

poll.cファイルを標準入力からのリダイレクトとした場合,POLLINとPOLLOUTの両方の表示がでます.

ppoll関数の使い方

ppoll関数の使い方は以下になります.

実行結果は以下になります.同様です.

epollファミリー関数

epollファミリー関数を紹介します.

※正確にはepoll関数はなくepollがプリフィックスについた関数群のことです.

epoll_create/epoll_create1関数

epoll_create/epoll_create1関数を紹介します.

epoll_create関数は新規のepollインスタンスを作成し,そのファイルディスクリプタを返します.

epoll_create1関数は,flagsが0の場合,現在では使われていないsize引数がなくなっている点を除けばepoll_create関数と同じです.

flagsに以下の値をビット毎の論理和(OR)で指定することで,異なる動作をさせることができます.

  • EPOLL_CLOEXEC:新しいファイルディスクリプタに対してclose-on-exec(FD_CLOEXEC)フラグを設定

epoll_ctl関数

epoll_ctl関数は,ファイルディスクリプタepfdが参照するepollインスタンスに対する操作を行います.

  • epfd:参照するファイルディスクリプタ
  • op:対象のファイルディスクリプタfdに対する操作
  • fd:対象のファイルディスクリプタ
  • event:ファイルディスクリプタfdにリンクされたオブジェクト

event引数のstruct epoll_event構造体(struct epoll_data構造体を含む)は以下になります.

eventsメンバは,利用可能なイベントタイプを使って構成された ビットセットです(詳細はリンク先参照).

epoll_wait/epoll_pwait関数

epoll_wait/epoll_pwait関数を紹介します.

epoll_wait関数は,ファイルディスクリプタepfdにより参照されるepollインスタンス上でイベントを待ちます.

eventsが指すバッファは,interest listにあるファイルディスクリプタのうち,何らかのイベントが利用可能なものについての情報をready listから返すために利用されます.

maxeventsまでがepoll_wait関数により返されます.

timeout引数はepoll_wait関数がブロックするミリ秒数を指定します.

時間はCLOCK_MONOTONICクロックに対して測定されます.

epoll_waitの呼び出しは,以下のいずれかが起こるまでブロックされます.

  • ファイルディスクリプターがイベントを配送した
  • 呼び出しがシグナルハンドラーにより割り込まれた
  • タイムアウトが満了した

epoll_wait関数とepoll_pwait関数の関係は,select関数とpselect関数の関係と同様です.

pselect関数と同様に,epoll_pwait関数を利用すると,アプリケーションはファイルディスクリプタが準備できた状態になるか,シグナルが捕捉されるまで,安全に待つことができます.

epollファミリー関数の使い方

epollファミリー関数の使い方は以下になります.

実行結果は以下になります.

select/pselect/poll/ppoll/epoll関数の違い

select/pselect/poll/ppoll/epoll関数の違いは下表になります.

項目select関数pselect関数poll関数ppoll関数epollファミリー関数
管理するファイルディスクリプタの確認の計算量\(\mathcal{O}(n)\)\(\mathcal{O}(n)\)\(\mathcal{O}(n)\)\(\mathcal{O}(n)\)\(\mathcal{O}(n)\)※
ファイルディスクリプタ数の上限FD_SETSIZE
(1,024の場合が多い)
FD_SETSIZE
(1,024の場合が多い)
なしなしなし
シグナルの捕捉なしありなしありあり

※ready状態のファイルディスクリプタのみを通知して処理するので,他の関数よりも管理するファイルディスクリプタが少なくなり,処理時間が短くなりやすい.

まとめ

C言語のselect/pselect/poll/ppoll/epoll関数の違いを紹介します.

細かい違いですが,まずは概要を理解しましょう!

C言語を独学で習得することは難しいです.

私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.

私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!

友だち追加

独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!

-C LANGUAGE, TECHNOLOGY
-, , , , , , , , ,