プロセス間通信（IPC）の手段とその使い方

## はじめに

プロセス間通信（Inter-Process Communication、IPC）は、複数のプロセスが情報を交換するためのメカニズム。IPCは、異なるプロセスがメモリ空間を共有せずにデータをやり取りするための手段を提供する。
## 1. パイプ（Pipes）

### 名前なしパイプ（Unnamed Pipes）
名前なしパイプは、親プロセスと子プロセス間でデータを一方向に通信するために使用される。

```python
import os

r, w = os.pipe()  # パイプの作成

pid = os.fork()  # プロセスの分岐

if pid > 0:  # 親プロセス
    os.close(r)  # 読み取り側を閉じる
    w = os.fdopen(w, 'w')
    w.write("Hello from parent process")
    w.close()
else:  # 子プロセス
    os.close(w)  # 書き込み側を閉じる
    r = os.fdopen(r)
    print("Child process received:", r.read())
    r.close()
```

### 名前付きパイプ（Named Pipes、FIFO）
名前付きパイプは、異なるプロセス間でデータを一方向に通信するために使用される。

```python
import os
import time

fifo = 'myfifo'

# 名前付きパイプの作成
if not os.path.exists(fifo):
    os.mkfifo(fifo)

pid = os.fork()

if pid > 0:  # 親プロセス
    with open(fifo, 'w') as f:
        f.write("Hello from parent process")
else:  # 子プロセス
    time.sleep(1)  # 親プロセスが書き込むまで待機
    with open(fifo, 'r') as f:
        print("Child process received:", f.read())
```

## 2. メッセージキュー（Message Queues）

メッセージキューは、複数のプロセス間でデータを送受信するためのキュー。

```python
import sysv_ipc

key = 1234  # メッセージキューキー
mq = sysv_ipc.MessageQueue(key, sysv_ipc.IPC_CREAT)

pid = os.fork()

if pid > 0:  # 親プロセス
    mq.send(b"Hello from parent process")
else:  # 子プロセス
    message, _ = mq.receive()
    print("Child process received:", message.decode())
```

## 3. 共有メモリ（Shared Memory）

共有メモリは、複数のプロセスが直接メモリを共有するための手段。

```python
import sysv_ipc

key = 5678  # 共有メモリキー
memory = sysv_ipc.SharedMemory(key, sysv_ipc.IPC_CREAT, size=1024)

pid = os.fork()

if pid > 0:  # 親プロセス
    memory.write(b"Hello from parent process")
else:  # 子プロセス
    time.sleep(1)  # 親プロセスが書き込むまで待機
    print("Child process received:", memory.read().decode().strip())
```

## 4. ソケット（Sockets）

ソケットは、ネットワーク通信だけでなく、同じホスト内のプロセス間通信にも使用できる。

```python
import socket

server_address = './uds_socket'

# サーバー
if os.fork() == 0:
    with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as server:
        server.bind(server_address)
        server.listen(1)
        connection, _ = server.accept()
        with connection:
            print("Server received:", connection.recv(1024).decode())
else:  # クライアント
    with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client:
        time.sleep(1)  # サーバーが準備できるまで待機
        client.connect(server_address)
        client.sendall(b"Hello from client")
```

## 5. 信号（Signals）

信号は、プロセス間で簡単な通知を行うための手段。

```python
import signal
import os
import time

def handler(signum, frame):
    print("Signal received:", signum)

signal.signal(signal.SIGUSR1, handler)

pid = os.fork()

if pid > 0:  # 親プロセス
    time.sleep(1)
    os.kill(pid, signal.SIGUSR1)
else:  # 子プロセス
    time.sleep(2)
```

## 6. セマフォ（Semaphores）

セマフォは、複数のプロセス間でリソースのアクセス制御を行うための手段。

```python
import sysv_ipc
import os

key = 9876  # セマフォキー
sem = sysv_ipc.Semaphore(key, sysv_ipc.IPC_CREAT, initial_value=1)

pid = os.fork()

if pid > 0:  # 親プロセス
    sem.acquire()
    print("Parent process entering critical section")
    time.sleep(2)
    print("Parent process leaving critical section")
    sem.release()
else:  # 子プロセス
    sem.acquire()
    print("Child process entering critical section")
    time.sleep(2)
    print("Child process leaving critical section")
    sem.release()
```