メールスロットを使用してプロセス間通信を行っています。
http://www.kumei.ne.jp/c_lang/sdk3/sdk_250.htm
http://msdn.microsoft.com/ja-jp/library/cc429615.aspx
ここで質問させて頂きます。
メールスロットは、メールスロットを介して、送信側プロセスのメッセージを
受信側プロセスで受信するものですが、送信する時、また、受信する時に
メールスロットに対して排他制御をする必要はないのでしょうか?
それとも、Windowsの方で排他しているのでしょうか?
具体的には、
WriteFileする時
ReadFileする時
です。
なお、WriteFileするのは複数(2つ以上)のプロセスのケースもあります。
よろしくお願いします。
基本的に排他制御する必要はありません。
メールスロットの読み書きはメッセージ単位で行われ、分割して読み書きすることは出来ないはずです。
また、最初に送ったメッセージが最初に読まれるFIFOのキューに貯められており、順番を変更したり途中から読むことも出来ません。
したがって、メールスロットの読み書きに関しては、排他制御する必要がありません。
http://msdn.microsoft.com/en-us/library/aa365576.aspx
ただ、サーバ(ReadFile)側でハンドルを複製や継承して複数で受け取っている場合、GetMailslotInfo後ReadFileするまでの間に別プロセスやスレッドが取り出してしまう可能性はあります。
この場合、排他制御すれば防げますが、メッセージの最大サイズを決めて、それで受け取るようにすればGetMailslotInfoが必要なくなると思います。
----
[追記]
下記2つの関数をセットとして考えた場合、
その前後に排他処理が必要ということでしょうか?
GetMailslotInfo
ReadFile
必要か?と言われると、場合により必要であれば、という答えになります。
以下、http://msdn.microsoft.com/en-us/library/aa365130.aspx より引用します。
This handle must be used when a process reads messages from the mailslot. Only the process that creates a mailslot or has obtained the handle by some other mechanism (such as inheritance) can read from the mailslot.
訳:このハンドルはプロセスがメールスロットからメッセージを読みだす際に使用しなければならない。メールスロットを作成(訳注1)した、または(継承(訳注2)等)他の仕組みによりハンドルを与えられたプロセスのみがメールスロットから読み出せる。
また、http://msdn.microsoft.com/ja-jp/library/cc429615.aspx より
指定された名前のメールスロットが既に存在している場合は、エラーになります。
よって、スレッドを作ったり、明示的に継承可能にして子プロセスを作ったりしなければ、読み出し可能なのは単一プロセス単一スレッドに限られます(CreateFile関数で作ったハンドルでは読み出しは出来ない)。
読み出し可能なのが単一プロセス単一スレッドであれば排他処理は意味がありません。
子プロセスを作ってメールスロットハンドルを継承させて、親プロセスと子プロセス、または複数の子プロセスで読み出しをするのであれば排他制御が必要かもしれません。
マルチスレッド環境でも同様な配慮が必要と思われますが、マルチスレッドなら当たり前と言えば当たり前な事ではあります。
あと、補足的に。
http://msdn.microsoft.com/en-us/library/aa365467.aspx
If ReadFile attempts to read from a mailslot that has a buffer that is too small, the function returns FALSE and GetLastError returns ERROR_INSUFFICIENT_BUFFER.
訳:小さすぎるバッファによりメールスロットからの読み込みを試みた場合、FALSEを返し、GetLastErrorがERROR_INSUFFICIENT_BUFFERを返す。
おそらくレコードより小さな単位での読み出しは失敗するのだと思われます。
また、バッファサイズが大きくとも、読み込みは1レコードのみと思われます。
したがって戻り値やエラー処理を適切に行えば、効率低下以外の大きな問題は発生しないと思われます。
ただ、一番確実なのはサンプルコード書いてみることです。
>WriteFileする時
>ReadFileする時
CreateFile関数の第三引数でFILE_SHARE_READとしていますので、他からの同時書き込みは禁止ですが、他からの読み出しは許可ということになります
http://msdn.microsoft.com/ja-jp/library/cc429198.aspx
雑談ですが、
質問タイトルがメールスロットだったので、キャンセルなさった質問(http://q.hatena.ne.jp/1315259024)のほうはタイトルだけでスルーしてました
「Windows C言語のファイル操作排他制御」などであったならば見ていたかも・・・何が気を引くのか・・・タイトルって大事
回答ありがとうございます。
CreateFile関数の第三引数は、
FILE_SHARE_WRITE | FILE_SHARE_READ
を指定しています。
ということは、同時読み書き許可と考えてよいのでしょうか?
基本的に排他制御する必要はありません。
メールスロットの読み書きはメッセージ単位で行われ、分割して読み書きすることは出来ないはずです。
また、最初に送ったメッセージが最初に読まれるFIFOのキューに貯められており、順番を変更したり途中から読むことも出来ません。
したがって、メールスロットの読み書きに関しては、排他制御する必要がありません。
http://msdn.microsoft.com/en-us/library/aa365576.aspx
ただ、サーバ(ReadFile)側でハンドルを複製や継承して複数で受け取っている場合、GetMailslotInfo後ReadFileするまでの間に別プロセスやスレッドが取り出してしまう可能性はあります。
この場合、排他制御すれば防げますが、メッセージの最大サイズを決めて、それで受け取るようにすればGetMailslotInfoが必要なくなると思います。
----
[追記]
下記2つの関数をセットとして考えた場合、
その前後に排他処理が必要ということでしょうか?
GetMailslotInfo
ReadFile
必要か?と言われると、場合により必要であれば、という答えになります。
以下、http://msdn.microsoft.com/en-us/library/aa365130.aspx より引用します。
This handle must be used when a process reads messages from the mailslot. Only the process that creates a mailslot or has obtained the handle by some other mechanism (such as inheritance) can read from the mailslot.
訳:このハンドルはプロセスがメールスロットからメッセージを読みだす際に使用しなければならない。メールスロットを作成(訳注1)した、または(継承(訳注2)等)他の仕組みによりハンドルを与えられたプロセスのみがメールスロットから読み出せる。
また、http://msdn.microsoft.com/ja-jp/library/cc429615.aspx より
指定された名前のメールスロットが既に存在している場合は、エラーになります。
よって、スレッドを作ったり、明示的に継承可能にして子プロセスを作ったりしなければ、読み出し可能なのは単一プロセス単一スレッドに限られます(CreateFile関数で作ったハンドルでは読み出しは出来ない)。
読み出し可能なのが単一プロセス単一スレッドであれば排他処理は意味がありません。
子プロセスを作ってメールスロットハンドルを継承させて、親プロセスと子プロセス、または複数の子プロセスで読み出しをするのであれば排他制御が必要かもしれません。
マルチスレッド環境でも同様な配慮が必要と思われますが、マルチスレッドなら当たり前と言えば当たり前な事ではあります。
あと、補足的に。
http://msdn.microsoft.com/en-us/library/aa365467.aspx
If ReadFile attempts to read from a mailslot that has a buffer that is too small, the function returns FALSE and GetLastError returns ERROR_INSUFFICIENT_BUFFER.
訳:小さすぎるバッファによりメールスロットからの読み込みを試みた場合、FALSEを返し、GetLastErrorがERROR_INSUFFICIENT_BUFFERを返す。
おそらくレコードより小さな単位での読み出しは失敗するのだと思われます。
また、バッファサイズが大きくとも、読み込みは1レコードのみと思われます。
したがって戻り値やエラー処理を適切に行えば、効率低下以外の大きな問題は発生しないと思われます。
ただ、一番確実なのはサンプルコード書いてみることです。
回答ありがとうございます。
下記2つの関数をセットとして考えた場合、
その前後に排他処理が必要ということでしょうか?
GetMailslotInfo
ReadFile
メッセージのサイズは不定です。
回答ありがとうございます。
下記2つの関数をセットとして考えた場合、
その前後に排他処理が必要ということでしょうか?
GetMailslotInfo
ReadFile
メッセージのサイズは不定です。