Linuxカーネル: プロセス間の通信方法
1. パイプ (Pipe)
pipe()
システムコールを使って作成される、プロセス間通信のためのメカニズムを指します。このパイプは、一方のプロセスがデータを書き込み、もう一方のプロセスがそのデータを読み取ることができる、一方向のデータストリームを提供します。
使用例:
#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)
メッセージキューはプロセス間での非同期通信をサポートする仕組みで、メッセージの送信と受信を行います。
使用例:
#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)
セマフォは、複数のプロセスやスレッドが共有リソースにアクセスする際の同期を取るための手段です。
使用例:
#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;
}
コードの各部分とその説明
- セマフォの初期化
if (sem_init(&semaphore, 0, 1) != 0) {
perror("sem_init");
exit(EXIT_FAILURE);
}
この部分では、sem_init
を使用してセマフォを初期化しています。ここで、セマフォの初期値を1
に設定しています。この1
は、一度にクリティカルセクションに入ることができるスレッドの最大数を示しています。
- スレッドがクリティカルセクションに入る
sem_wait(&semaphore);
このsem_wait
関数は、セマフォの値をデクリメントします。セマフォの値が0
より大きい場合、デクリメントして続行します。しかし、セマフォの値が0
の場合、この関数はブロックされ、セマフォの値が増加するまで待ちます。
- クリティカルセクション
printf("Thread %ld: Enter critical section.\n", (long)arg);
sleep(2);
printf("Thread %ld: Exit critical section.\n", (long)arg);
この部分はクリティカルセクションとしています。sleep(2);
は、スレッドがクリティカルセクション内であることを示すための模擬的な処理時間を意味しています。
- スレッドがクリティカルセクションから出る
sem_post(&semaphore);
sem_post
関数はセマフォの値をインクリメントします。この関数を呼び出すと、前述のsem_wait
でブロックされていた他のスレッドが解放され、クリティカルセクションに入ることができるようになります。
コード全体を通じて、sem_wait
とsem_post
によって、同時にクリティカルセクションに入ろうとする2つのスレッドの動作が制御されています。その結果、クリティカルセクションには一度に1つのスレッドしか入ることができません。
4. 共有メモリ (Shared Memory)
共有メモリは、複数のプロセス間でデータを共有するためのメカニズムです。
使用例:
#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);
}