出处:仮想デバイスドライバを利用したプロセス間通信について http://cheesy.dip.jp/tutorialog/archives/6
仮想デバイスドライバを利用したプロセス間通信について説明します。といってもよくわからないと思うので、ちゃんと説明します。
Unixでプロセス間通信というと、ソケットを使ったもの、パイプを使ったもの、共有メモリを使ったもの等がありますが、それぞれ長所・短所があると思います。
ものすごく簡単に言うと、
ソケットでは、
- 複数マシン間での通信が可能
- 通信処理のオーバーヘッドが大きい(コネクション開始・終了処理も含め)
パイプでは、
- ソケットより通信処理のオーバーヘッドが少ない
- 親子関係のプロセスに限定される
共有メモリでは、
- シンプルで高速
- 書き込み・読み取りの同期をとるのが難しい
等が挙げられると思います。
共有メモリがシンプルかつ高速ですばらしいのですが、アプリケーションレベルで同期をとるのが難しいという問題があります。そこで、ここでは、共有メモリによるプロセス間通信における同期機構を、仮想デバイスドライバを使って行う手法を説明しようと思います。
開発環境は、FedoraCore4(2.6.11-1.1369_FC4)、gcc 4.0.0、GNU make 3.80です。
Linuxのデバイスドライバについては、私も詳しくないですが、以下のページが参考になると思いますので、書いたことのない方は一度見てみてください。
The Linux Kernel Module Programming Guide
Linux Kernel Module programming(Kernel 2.4)概要
同期の仕組みですが、デバイスドライバにpoll関数を実装し、そこで読み込みと書き込みの待ち列を設定します。書き込み(write)後に読み込み可能
になったら読み込みの待ち列に対して、wake_upを実行します。ユーザ側のプロセスでは、デバイスドライバをselect(2)で待ち(poll関数が呼び出
される)、読み込み可能になり次第、カーネルから起こされ読み込み処理を実行できるようになります。 書き込みも同じ原理で動きます。しかし、読み込
みと書き込みは同時には実行できません。(当たり前ですが。)
実装
次に、実際のソースについて解説します。デバイスドライバといっても、本物のデバイスを操作するわけではなく、同期を取るだけで実際の通信データも
扱わないので非常に単純です。ソースはこちらです。(sync.c)
コンパイル
ソースのコンパイルは以下のMakefileを使います
% make
make -C /lib/modules/2.6.11-1.1369_FC4/build M=`pwd` V=1 modules ...
モジュールをカーネルに組み込む
コンパイルがうまくいくと、モジュールファイルsynk.koができていると思います。後は組み込んで、デバイスファイルを作るだけです。
% sudo /sbin/insmod sync.ko % sudo mknod /dev/sync c 100 0
以上で、プロセス間同期用のデバイスファイルの作成と組み込みは終わりです。
動作テスト
次は実際に、書き込み、読み込みの2プロセス間でプロセス間通信をさせてみます。
まずは書き込みのプログラムです。(map_write.c)次に読み込み側です。(map_read.c)
コンパイルし、実際に動かしてみます。
% gcc map_write.c -o map_write % gcc map_read.c -o map_read
読み込みプロセスを実行すると、書き込みがあるまで待ちます。
% ./map_read selecting ...
書き込みを実行すると、書き込み可能なため待つことなく、書き込みを実行し、その直後に
読み込み可能となり、共有メモリからのデータを受け取ることができます。% sudo ./map_write selecting ... wait released.
% ./map_read selecting ... get data from mapped area [Hello, are you getting my request ?]
まとめ
知识点补充今回は、共有メモリにおけるプロセス間通信の欠点を補うような同期機構を、仮想デバイスファイルを利用することによって実現しました。
この機構を利用すれば、同一マシン間での高速なプロセス間のデータ受け渡しが可能になるので、パフォーマンスが重要になってくるよう
なアプリケーションで役に立つかもしれません。
sem_init() initialises the unnamed semaphore at the address pointed to by sem.sem_init - initialise an unnamed semaphore
Synopsis
#include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value);
Description
The value argument specifies the initial value for the semaphore.The pshared argument
indicates whether this semaphore is to be shared between the threads of a process,
or between processes.