メールスロットの排他制御について


メールスロットを使用してプロセス間通信を行っています。
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つ以上)のプロセスのケースもあります。

よろしくお願いします。

回答の条件
  • URL必須
  • 1人3回まで
  • 登録:
  • 終了:2011/09/12 22:35:16
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:TransFreeBSD No.3

回答回数668ベストアンサー獲得回数268

ポイント100pt

基本的に排他制御する必要はありません。

メールスロットの読み書きはメッセージ単位で行われ、分割して読み書きすることは出来ないはずです。

また、最初に送ったメッセージが最初に読まれる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レコードのみと思われます。

したがって戻り値やエラー処理を適切に行えば、効率低下以外の大きな問題は発生しないと思われます。


ただ、一番確実なのはサンプルコード書いてみることです。

id:futurista

回答ありがとうございます。

下記2つの関数をセットとして考えた場合、

その前後に排他処理が必要ということでしょうか?

GetMailslotInfo

ReadFile

メッセージのサイズは不定です。

2011/09/11 13:21:06

その他の回答2件)

id:windofjuly No.2

回答回数2625ベストアンサー獲得回数1149

ポイント33pt

>WriteFileする時

>ReadFileする時

CreateFile関数の第三引数でFILE_SHARE_READとしていますので、他からの同時書き込みは禁止ですが、他からの読み出しは許可ということになります

http://msdn.microsoft.com/ja-jp/library/cc429198.aspx

 

雑談ですが、

質問タイトルがメールスロットだったので、キャンセルなさった質問(http://q.hatena.ne.jp/1315259024)のほうはタイトルだけでスルーしてました

「Windows C言語のファイル操作排他制御」などであったならば見ていたかも・・・何が気を引くのか・・・タイトルって大事

id:futurista

回答ありがとうございます。

CreateFile関数の第三引数は、

FILE_SHARE_WRITE | FILE_SHARE_READ

を指定しています。

ということは、同時読み書き許可と考えてよいのでしょうか?

2011/09/11 12:58:31
id:TransFreeBSD No.3

回答回数668ベストアンサー獲得回数268ここでベストアンサー

ポイント100pt

基本的に排他制御する必要はありません。

メールスロットの読み書きはメッセージ単位で行われ、分割して読み書きすることは出来ないはずです。

また、最初に送ったメッセージが最初に読まれる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レコードのみと思われます。

したがって戻り値やエラー処理を適切に行えば、効率低下以外の大きな問題は発生しないと思われます。


ただ、一番確実なのはサンプルコード書いてみることです。

id:futurista

回答ありがとうございます。

下記2つの関数をセットとして考えた場合、

その前後に排他処理が必要ということでしょうか?

GetMailslotInfo

ReadFile

メッセージのサイズは不定です。

2011/09/11 13:21:06
  • id:windofjuly
    うぃんど 2011/09/06 22:47:37
    じゅぴたー(id:Jupiter2100)さんの回答は間違いがあります
     
    >OS側で順次読み出し/書き込みをしています
    OS側が制御しているのではなく、プログラムがWin32APIを使うことで制御しています
    仮にWin32APIに従わない(利用しない)プログラムがあるとすれば、排他制御は崩壊してしまいます(そのためAPIを使っているはずです)
     
    リンク先も少しピントがずれていると思います
    メールスロットの概要は良しとして、Delphiの例を持ってくる意味が不明です
    質問文のリンク先を見れば言語はCであることが判ると思います
     
    ポイント付き回答でよく見かけますし、ハイクでも他の人を執拗に追いかけて指摘していますが、ご自身の行動も見直されたほうがよろしいかと思います
    木星帰りさんの文章構成や行動パターンは追放された有名アカウントを髣髴とされるものがあります
    実力ある古参ユーザーだと思いますが悪いパターンの真似はやめておいたほうが身のためだと思います
  • id:TransFreeBSD
    メールスロットのメモリ領域ってAPIを経由せずにアクセス可能なんでしょうか?
    公開されていない気がするんですが。
    あと、CreateFileで作った方はクライアント用で、読み込み出来ませんよ。
  • id:a-kuma3
    >メールスロットのメモリ領域ってAPIを経由せずにアクセス可能なんでしょうか?
    昔の記憶だよりですが、メールスロットって、Netbios をラップした API だったと思うんです。
    だから、「メモリ領域をアクセス」というのとは、ちょっと違うはず。

    一応、MSDN の URL くらい貼っておくかな。
    http://msdn.microsoft.com/en-us/library/aa365147
  • id:windofjuly
    うぃんど 2011/09/06 23:26:23
    質問文の「具体的には」の記述に従い、ファイル操作の排他制御の部分について論じています
  • id:a-kuma3
    あ、根っこの方の URL 貼ってましたね >id:TransFreeBSD さん
  • id:TransFreeBSD
    メールスロットはIPCで、マシン間を越えるときに越えるときにNetBIOSを使っているというだけで、キュー自体はサーバプロセスのあるマシンのメモリ上にあるとされています。
    また、その通信をdatagramと表現されていますし、マシン間を越える場合の最大サイズは424バイトとなってますから、おそらく1メッセージ(メールスロットではレコードというらしい)1パケットだけの単純なものなのでしょう。

    というか、非常に単純で単機能なサービスなので、なんというか排他制御とか考えるまでもな用途向けな気がします。
  • id:TransFreeBSD
    追記しました

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません