システムコールと関数呼び出しの違いは何ですか? fopen()はシステム呼び出しですか、それとも関数呼び出しですか?
システムコールはカーネルコードへの呼び出しであり、通常は割り込みを実行することによって実行されます。割り込みにより、カーネルが引き継いで要求されたアクションを実行し、アプリケーションに制御を戻します。このモード切り替えが、システムコールの実行が同等のアプリケーションレベルの関数よりも遅い理由です。
fopen
は、Cライブラリの関数であり、内部で1つ以上のシステムコールを実行します。一般に、Cプログラマは、Cライブラリがシステムコールをラップするため、システムコールを使用する必要はほとんどありません。
fopenは関数呼び出しです。
システムコールは、リソースを管理する基盤となるOSと対話します。 syscallを作成したプロセスの状態を保存するために多くの手順を実行する必要があるため、そのmagnitudの注文は関数呼び出しよりも高価です。
* nixシステムでは、fopenはopenをラップして、システムコールを作成します(openはC-syscallのラッパーです)。同じことがfread/read、fwrite/writeなどでも起こります。
ここ unix syscallによって実行されるタスクの素敵な説明があります。
実際には、システムコールは関数呼び出しとは関係ありません。これら2つのメカニズムの唯一の共通点は、どちらも呼び出し元にサービスを提供することです。
スレッド実行の観点からシステムコールを確認する:
システムコールは、アプリケーションモードプログラムが下線OSが提供するサービスを要求する機能です。システムコールは、実行中のスレッドをユーザーモードからカーネルモードに移行し、システムコールハンドラー関数を実行してから、ユーザーモードに戻ります。
Syscallパラメータ:
システムコールのパラメータは(syscall番号、params ...)です。 paramsの意味と形式は、syscall番号によって異なります。
ユーザーランドプログラムに提供されるsyscallライブラリの観点から:
ユーザーモードプログラムは通常、glibcのライブラリを呼び出してシステムコールを呼び出します。たとえば、glibcのopen()関数:
Linuxを使用している場合は、アプリケーションによって実行されるシステムコールを監視できます。
strace appname ...
その出力は、libc内で何が起こっているか、および実際にシステムコールである関数についての良い洞察を与えるかもしれません。
システムコール は、実際にはカーネルスペースによって実行されるAPIを呼び出します。これはすべての関連コストとともに想定されます(詳細については、Wikiまたはこのリンクを参照してください)
関数呼び出しは、ユーザー空間のコードの一部への呼び出しです。
ただし、関数呼び出しは、その実行過程でシステムコールを実行する可能性がある関数である可能性があることに注意してください。「fopen」はそのような例の1つです。したがって、fopen自体の呼び出しは関数の呼び出しですが、システムコールが実際のIOを処理しないということではありません。
質問はすでに優れた回答を持っていますが、何かを追加できると思います(- ostep からの1つのセグメント)
時々、システムコールと関数コールは同じ署名を持っています、例えば、open()
:
open()
-システムコール_--- ~/Documents » man open(2)
OPEN(2) Linux Programmer's Manual OPEN(2)
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
...
_
open()
-関数呼び出し_$ man open(3)
--- ~/Documents »
OPEN(3P) POSIX Programmer's Manual OPEN(3P)
...
int open(const char *path, int oflag, ...);
...
_
open()
やread()
などのシステムコールの呼び出しが、なぜ正確に次のようになるのか疑問に思われるかもしれませんCでの典型的な手続き呼び出し;つまり、プロシージャコールのように見える場合、システムはそれがシステムコールであることをどのように認識しますか、そしてすべて正しいことをしますか?単純な理由:これはプロシージャコールですが、その中に隠されていますプロシージャコールは有名なトラップ命令です。より具体的には、(たとえば)open()
を呼び出すと、Cライブラリにプロシージャコールが実行されます。そこでは、open()
または他のシステムコールのいずれが提供されても、ライブラリはカーネルとの合意された呼び出し規約を使用しますよく知られた場所(たとえば、スタック、または特定のレジスタ)は、system-call番号を既知の場所に(再び、stackまたはaregister)、そして前述のトラップ命令。 trapの後のライブラリ内のコードは、戻り値をアンパックし、システムコールを発行したプログラムに制御を返します。したがって、システムコールを作成するCライブラリの部分は、引数を処理するために規則に従って慎重に実行する必要があるため、アセンブリで手動でコーディングされます。値を正しく返し、ハードウェア固有のトラップ命令を実行します。これで、OSにtrapにアセンブリコードを書く必要がない理由がわかりました。誰かがあなたのためにそのアセンブリをすでに書いています。
この議論に追加する視点は、一般に最も楽観的なケースでの関数呼び出しには、x86でいくつかの8ビット命令(平均4-10)のオーバーヘッドがあるということです。
システムコールには以下のプロパティがあります。
これらの3つの基本的な理由(おそらくもっと多い)のため、可能な場合はシステムコールの量を減らす必要があります。たとえば、ネットワークシステムソフトウェアは、ソケットハンドル(および接続で使用される他のアプリケーション固有の内部データ構造)を保持して新しい接続、なぜカーネルを気にするのですか?
ソフトウェアは逆さまのピラミッドのように構築されていることに注意してください。システムコールは基本です。
他の人が提示した図を完成させるために、fopen
は 一般に実装されています であり、open
のラッパーとしても使用できます。これもユーザーがアクセスできる関数です。 fopen
は、ある意味でopen
よりも高いレベルです。これは、FILE*
構造体がユーザーのカプセル化要素を返すためです。一部のユーザーは、特別なニーズのためにopen
を直接使用します。したがって、fopen
を「システムコール」と呼ぶのは適切ではありません。 open
もユーザーが呼び出し可能な関数であるため、システムコールを直接実行しません。
fopen
は関数呼び出しですが、最終的に「システム」(OS)によって処理されるため、システムコールと呼ばれることもあります。 fopen
は Cランタイムライブラリ に組み込まれています。
システムコールは、ハードウェアにアクセスするための特権が必要なため、ユーザーspceではなく、カーネルレベルで実行されます。
したがって、ユーザー空間でプログラミングし、C言語でfopen
のような通常の関数呼び出しを行うと、libcは通常、この関数を特定のコードコードにラップし、割り込みが生成されてユーザー空間からカーネル空間に切り替わり、その後カーネル空間に入るハードウェアレベルで関数呼び出しの機能を実行するために必要なシステムコールは、カーネル空間で実行されます。