Linuxカーネル: プロセス間の通信方法

# Linuxカーネル: プロセス間の通信方法

## 1. パイプ (Pipe)

`pipe()` システムコールを使って作成される、プロセス間通信のためのメカニズムを指します。このパイプは、一方のプロセスがデータを書き込み、もう一方のプロセスがそのデータを読み取ることができる、一方向のデータストリームを提供します。

### 使用例:

```c
#include <stdio.h>
#include <unistd.h>

int main() {
    int pipe_fd[2];
    char buf[100];

    pipe(pipe_fd);

    if (fork() == 0) {  // Child process
        close(pipe_fd[0]);  // Close reading end
        write(pipe_fd[1], "Hello, parent!", 15);
        close(pipe_fd[1]);
    } else {  // Parent process
        close(pipe_fd[1]);  // Close writing end
        read(pipe_fd[0], buf, sizeof(buf));
        printf("Received: %s\n", buf);
        close(pipe_fd[0]);
    }

    return 0;
}
```

## 2. メッセージキュー (Message Queue)

メッセージキューはプロセス間での非同期通信をサポートする仕組みで、メッセージの送信と受信を行います。

### 使用例:

```c
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct msgbuf {
    long mtype;
    char mtext[100];
};

int main() {
    int msqid;
    struct msgbuf buf;
    key_t key = 1234;

    if ((msqid = msgget(key, 0666)) < 0) {
        perror("msgget");
        exit(1);
    }

    buf.mtype = 1;

    if (fork() == 0) {  // Child process
        sprintf(buf.mtext, "Hello from child");
        msgsnd(msqid, &buf, sizeof(buf.mtext), 0);
    } else {  // Parent process
        msgrcv(msqid, &buf, sizeof(buf.mtext), 1, 0);
        printf("Received: %s\n", buf.mtext);
    }

    return 0;
}
```

## 3. セマフォ (Semaphore)

セマフォは、複数のプロセスやスレッドが共有リソースにアクセスする際の同期を取るための手段です。

### 使用例:

```c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

// セマフォの定義
sem_t semaphore;

void* thread_function(void* arg) {
    sem_wait(&semaphore); // セマフォを減少させる
    printf("Thread %ld: Enter critical section.\n", (long)arg);
    
    // クリティカルセクション: この中で行われる処理は一度に1つのスレッドしか実行できない
    sleep(2); // 擬似的な処理時間

    printf("Thread %ld: Exit critical section.\n", (long)arg);
    sem_post(&semaphore); // セマフォを増加させる

    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    // セマフォの初期化 (初期値を1に設定)
    if (sem_init(&semaphore, 0, 1) != 0) {
        perror("sem_init");
        exit(EXIT_FAILURE);
    }

    // スレッドの作成
    pthread_create(&thread1, NULL, thread_function, (void*)1);
    pthread_create(&thread2, NULL, thread_function, (void*)2);

    // スレッドが終了するのを待つ
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    // セマフォの破棄
    sem_destroy(&semaphore);

    return 0;
}

```

### コードの各部分とその説明

1. **セマフォの初期化**
```c
if (sem_init(&semaphore, 0, 1) != 0) {
    perror("sem_init");
    exit(EXIT_FAILURE);
}
```
この部分では、`sem_init`を使用してセマフォを初期化しています。ここで、セマフォの初期値を`1`に設定しています。この`1`は、一度にクリティカルセクションに入ることができるスレッドの最大数を示しています。

2. **スレッドがクリティカルセクションに入る**
```c
sem_wait(&semaphore);
```
この`sem_wait`関数は、セマフォの値をデクリメントします。セマフォの値が`0`より大きい場合、デクリメントして続行します。しかし、セマフォの値が`0`の場合、この関数はブロックされ、セマフォの値が増加するまで待ちます。

3. **クリティカルセクション**
```c
printf("Thread %ld: Enter critical section.\n", (long)arg);
sleep(2);
printf("Thread %ld: Exit critical section.\n", (long)arg);
```
この部分はクリティカルセクションとしています。`sleep(2);`は、スレッドがクリティカルセクション内であることを示すための模擬的な処理時間を意味しています。

4. **スレッドがクリティカルセクションから出る**
```c
sem_post(&semaphore);
```
`sem_post`関数はセマフォの値をインクリメントします。この関数を呼び出すと、前述の`sem_wait`でブロックされていた他のスレッドが解放され、クリティカルセクションに入ることができるようになります。

コード全体を通じて、`sem_wait`と`sem_post`によって、同時にクリティカルセクションに入ろうとする2つのスレッドの動作が制御されています。その結果、クリティカルセクションには一度に1つのスレッドしか入ることができません。

## 4. 共有メモリ (Shared Memory)

共有メモリは、複数のプロセス間でデータを共有するためのメカニズムです。

### 使用例:

```c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>

#define SHMSZ     27

int main() {
    int shmid;
    key_t key;
    char *shm, *s;

    key = 5678;

    if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
        perror("shmget");
        exit(1);
    }

    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
        perror("shmat");
        exit(1);
    }

    s = shm;

    for (char c = 'a'; c <= 'z'; c++) {
        *s++ = c;
    }

    *s = '\0';

    while (*shm != '*')
        sleep(1);

    exit(0);
}
```