34711


C#にて、セマフォのやり方についての質問です。

プロセスCにWndProcのプロシージャを起動させておきます。  
プロセスA,BはプロセスCにプロセス間通信にてwinメッセージを送ります。  
プロセスCは受け取ったWinメッセージによって、データベースへアクセスし処理を行います。

プロセスA →  
プロセスC  
プロセスB →  
(A,B,Cは別々のアプリです)

以前、プロセスAとプロセスBで2つ同時にWinメッセージが来た際に、処理としては1つの  
Winメッセージの処理を終了してから、もう1つのWinメッセージの処理を行うという回答を  
頂きました。  
(今回はプロセスCにデータベースへアクセスし処理をするという動作が新たに加わっています。)

質問は、シングルスレッド時のセマフォの取得の仕方をご教授願いたいと思っております。  
上記の以前の質問の回答からプロセスCはシングルスレッドであるため、セマフォを取得する必要はないと思うのですが、  
一応念のため、セマフォを取得し同時データベースへアクセスし処理を行わないようにしたいと思っています。  
(同時に処理を行うということはないと思うのですが・・・)

やり方をご教授いただければ幸いです。よろしくお願いいたします。  
雑なコードで申し訳ございません。  
プロセスCのWndProc↓↓↓

[code]

        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            protected override void WndProc(ref Message m)
            {
                const int WM_M = ****;//プロセスA,BからWinメッセージ
                base.WndProc(ref m);
                if (m.Msg == WM_CHAR)
                {
    　　　　　　　　　datbase db = new datbase;
                    db.aaaa(ref m);/* データベースアクセスメソッド */
                }
                else
                {
                    base.WndProc(ref m);
                }
            }
        }
    
[/code]

datbaseクラス↓↓↓

[code]

        public class datbase
        {
            public void aaaa()
            {
                if (プロセスA)
                {
                    セマフォ取得;
                    データベースアクセスして処理;
                    セマフォ解放;
                }
                else if (プロセスB)
                {
                    セマフォ取得;
                    データベースアクセスして処理;
                    セマフォ解放;
                }
            }
        }
    
[/code]


CC BY-SA 3.0
2017-05-14T14:48:07.180
34706
2017-05-14T21:42:39.627
19213
question
c#
C#　セマフォについて


`System.Threading.Semaphore`を使用する場合、あらかじめ`Semaphore`のインスタンスを作成しておく必要があります。質問の要件では初期許可数`1`、同時実行数`1`ですので

[code]

    private Semaphore semaphore = new Semaphore(1, 1);
    
[/code]

とすればよいでしょう。なお並行する処理ではおなじセマフォを使用する必要がありますが、アセンブリやプロセスが異なりインスタンスを直接共有できない場合は名前付きのコンストラクターと`Semaphore.OpenExisting`メソッドを使用します。

`Semaphore`の取得と解放には`semaphore.WaitOne()`メソッドと`semaphore.Release()`を使用します。通常は確実に`Release`を呼び出すために`try-
finally`ステートメントで

[code]

    semaphore.WaitOne();
    try
    {
        データベースアクセスして処理;
    }
    finally
    {
        semaphore.Release();
    }
    
[/code]

と記述します。

なお同時実行数が`1`の場合は`Semaphore`ではなく`Mutex`や`EventWaitHandle`を利用することが出来ます。


CC BY-SA 3.0
2017-05-14T15:32:42.690
34708
2017-05-14T15:32:42.690
5750
34706
answer


>
[code]

>      protected override void WndProc(ref Message m)
>      {
>          const int WM_M = ****;//プロセスA,BからWinメッセージ
>          base.WndProc(ref m);
>          if (m.Msg == WM_CHAR)
>          {
>              datbase db = new datbase;
>              db.aaaa(ref m);/* データベースアクセスメソッド */
>          }
>          else
>          {
>              base.WndProc(ref m);
>          }
>      }
>  
[/code]

ここだけ見ても大量の問題を抱えています。

  * [`WM_CHAR`](https://msdn.microsoft.com/en-us/library/ms646276\(v=vs.85\).aspx)はキー入力のためのメッセージであり他の用途に使うべきではありません。（誤字かもしれませんが）
  * `m.Msg != WM_CHAR`の場合に`base.WndProc(ref m);`を２回呼び出すことになっています。どのような状況であっても`base`呼び出しは１回以下となるようにコードを記述する必要があります。
  * 全角空白を用いたインデントは避けるべきです。

そして最大の問題は **`WndProc`内で時間のかかる処理をしてはいけない**
ということです。データベースアクセスなどもってのほかです。`WndProc`とは別のスレッドでデータベースアクセスすべきです。

> 一応念のため、セマフォを取得し同時データベースへアクセスし処理を行わないようにしたいと思っています。  
>  (同時に処理を行うということはないと思うのですが・・・)

誰かの指示でしょうか？ 現状では **全く不要です**
。ただし前述のように`WndProc`とは別のスレッドでデータベースアクセスした際に必要となるスレッド同期について説明します。  
ここで「セマフォ」が語だけ先行していて意味を正確にとらえていない可能性があります。.NETには[同期プリミティブ](https://msdn.microsoft.com/ja-
jp/library/ms228964\(v=vs.110\).aspx)が多数用意されています。`Semaphore`のほかにもpgrhoさんの紹介された`Mutex`や`EventWaitHandle`もあります。１つの処理だけの実行を許可するという機能において`Semaphore`は適切ではなく[`Monitor`（クリティカルセクション）](https://msdn.microsoft.com/ja-
jp/library/system.threading.monitor\(v=vs.110\).aspx)が最適です。`Monitor`クラスを直接使う必要はなく、C#言語に用意されている[`lock`ステートメント](https://docs.microsoft.com/ja-
jp/dotnet/articles/csharp/language-reference/keywords/lock-statement)を推奨します。


CC BY-SA 3.0
2017-05-14T21:42:39.627
34711
2017-05-14T21:42:39.627
4236
34706
answer