Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

Windowsの匿名パイプ(無名パイプ)とは?CreatePipe()による親子プロセス間通信の実装例

Windowsの匿名パイプ(anonymous pipe)は、一般的なパイプと同じものであり、UNIX系OSにおけるパイプと非常によく似た挙動を示します。大きな特徴として、通信は一方向(半二重)であること、そしてパイプで通信するプロセス間に親子関係が必要である点が挙げられます。また、パイプへの読み書きには、通常のReadFile()およびWriteFile()関数がそのまま利用できます。

匿名パイプの作成方法

Windows APIでは、CreatePipe()関数を使ってパイプを生成します。この関数には以下の4つの引数を渡します。

  • パイプの読み取り側ハンドル

  • パイプの書き込み側ハンドル

  • ハンドルの継承可否などを指定するSECURITY_ATTRIBUTES構造体

  • パイプのバッファサイズ(バイト単位)

UNIX系システムとの大きな違いは、Windowsでは子プロセスがどの属性を継承するかをプログラマー自身が明示的に指定する必要があるという点です。具体的には、まずハンドルを継承可能にするようSECURITY_ATTRIBUTES構造体を初期化し、その後、子プロセスの標準入力(または標準出力)を、パイプの読み取り/書き込みハンドルへリダイレクトします。

子プロセスがパイプから読み取る場合は、親プロセス側で子の標準入力をパイプの読み取りハンドルへリダイレクトします。さらに、パイプは半二重であるため、子プロセスがパイプの書き込み側まで継承してしまわないよう、明示的に禁止しておく必要があります。

以下のコードは、親プロセスが匿名パイプを作成し、子プロセスと通信する例です。

サンプルコード:親プロセス側

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define BUFFER_SIZE 25

int main(void) {
    HANDLE ReadHandle, WriteHandle;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    char message[BUFFER_SIZE] = "Greetings";
    DWORD written;

    /* パイプを継承可能にするため、セキュリティ属性を設定 */
    SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};

    /* 構造体のメモリをゼロで初期化 */
    ZeroMemory(&pi, sizeof(pi));

    /* パイプを作成 */
    if (!CreatePipe(&ReadHandle, &WriteHandle, &sa, 0)) {
        fprintf(stderr, "CreatePipe Failed");
        return 1;
    }

    /* 子プロセス用にSTARTUPINFO構造体を設定 */
    GetStartupInfo(&si);
    si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);

    /* 標準入力をパイプの読み取り側へリダイレクト */
    si.hStdInput = ReadHandle;
    si.dwFlags = STARTF_USESTDHANDLES;

    /* 子プロセスがパイプの書き込み側を継承しないよう設定 */
    SetHandleInformation(WriteHandle, HANDLE_FLAG_INHERIT, 0);

    /* 子プロセスを生成 */
    CreateProcess(NULL, "child.exe", NULL, NULL,
                  TRUE, /* ハンドルを継承する */ 0, NULL, NULL, &si, &pi);

    /* 自分では使わない読み取り側を閉じる */
    CloseHandle(ReadHandle);

    /* 親プロセスがパイプへ書き込む */
    if (!WriteFile(WriteHandle, message, BUFFER_SIZE, &written, NULL))
        fprintf(stderr, "Error writing to pipe.");

    /* パイプの書き込み側を閉じる */
    CloseHandle(WriteHandle);

    /* 子プロセスの終了を待機 */
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return 0;
}

親プロセスは、パイプへ書き込む前に、自分では使用しない読み取り側のハンドルを先に閉じています。これにより、不要なハンドルが残ることによる問題を防いでいます。

サンプルコード:子プロセス側

パイプから読み取りを行う子プロセス(child.exe)のコードは以下の通りです。

#include <stdio.h>
#include <windows.h>
#define BUFFER_SIZE 25

int main(void) {
    HANDLE ReadHandle;
    CHAR buffer[BUFFER_SIZE];
    DWORD read;

    /* パイプの読み取りハンドルを標準入力から取得 */
    ReadHandle = GetStdHandle(STD_INPUT_HANDLE);

    /* 子プロセスがパイプから読み取る */
    if (ReadFile(ReadHandle, buffer, BUFFER_SIZE, &read, NULL))
        printf("child read %s", buffer);
    else
        fprintf(stderr, "Error reading from pipe");

    return 0;
}

このように、親プロセスがCreatePipe()で生成したパイプの読み取り側を子プロセスの標準入力に接続することで、WriteFile()で書き込まれたデータを子プロセスがReadFile()で受け取れるようになります。匿名パイプはシンプルながら、親子プロセス間の基本的なデータ連携を実現する重要なIPC(プロセス間通信)手法です。

  1. Windows 11 SEとは?教育向けOSの特徴・入手方法・対応アプリを徹底解説

    ChromebookとChrome OSが教育市場を大きく席巻する中、Microsoftは長年にわたりこの分野への本格参入を模索してきました。その切り札となるのが「Windows 11 SE」です。このOSはK-8(幼稚園〜中学校段階)の教室を想定して設計されており、使いやすさ、高いセキュリティ、そして低価格ながら性能が限られたPCへの適合性を重視しています。開発にあたってMicrosoftは、教育者、学校のIT担当者、管理者と緊密に連携しました。 Windows 11 SEは、同OS専用に設計された特別なデバイス上で動作することを前提としています。その代表格が、249ドルから提供されるMi

  2. 【Windows 10】Microsoftファミリー機能でお子様のアカウントを安全に管理する方法

    これまでの記事では、Windows 10でさまざまな種類のアカウントを作成する方法や、そのアクセス方法についてご紹介してきました。しかし、お子様のアカウントを具体的にどう管理すればよいのかについては、まだ詳しく触れていませんでした。実は、特定のアプリの使用を禁止したり、悪意のあるコンテンツを含むWebサイトへのアクセスをブロックしたりすることができるのです。 さらに、お子様がPCを使用できる時間帯と使用できない時間帯を細かく設定することも可能です。これらはすべて、Windows 10の設定アプリ内にある「アカウント」セクションから行えます。ただし、手順を進める前に、Windows 10で利用