5

これがどこで間違っているのかわかりません。基本的に、メッセージキューから受信してメッセージを処理するプログラムがあります。プログラムはいつでも停止できます。その場合、メッセージ ループは、プログラムが終了する前に処理を終了します。私は次のコードでこれを達成しようとしています:

private MessageQueue q;
private ManualResetEventSlim idle;

public void Start()
{
    idle = new ManualResetEventSlim();
    q.ReceiveCompleted += this.MessageQueue_ReceiveCompleted;    
    q.BeginReceive();
}    

public void Stop()
{ 
    this.q.Dispose();
    this.idle.Wait();    
}

private void MessageQueue_ReceiveCompleted(object sender, 
    ReceiveCompletedEventArgs e)
{
    Message inMsg;
    try
    {
        inMsg = e.Message;
    }
    catch (Exception ex)
    {
        this.idle.Set();
        return;
    }

    // Handle message

    this.q.BeginReceive();
}

おわかりのように、Stop メソッドはメッセージ キューを破棄し、アイドル状態の待機ハンドルが設定されるのを待ちます (これは、破棄時に ReceiveCompleted イベントが呼び出されるときに発生するはずですが、e.Message プロパティは除外する必要があります)。

ただし、メッセージ ループは続きます。メッセージ キューを破棄しましたが、メッセージ キューからの読み取りは引き続き行われ、例外ハンドラーは呼び出されません。つまり、idle.Wait 行は永久に待機します。

私の理解では、メッセージ キューを破棄すると、保留中の受信を終了してイベントを呼び出す必要がありますが、e.Message (または q.EndReceive) は例外をスローする必要があります。そうではありませんか?そうでない場合、他にどうすれば安全にメッセージ ループを終了できますか?

ありがとう

アップデート:

完全な例を次に示します (キューが存在すると仮定します)。

class Program
{
    static MessageQueue mq;
    static ManualResetEventSlim idleWH;

    static void Main(string[] args)
    {
        idleWH = new ManualResetEventSlim();

        Console.WriteLine("Opening...");
        using (mq = new MessageQueue(@".\private$\test"))
        {
            mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(int) });
            mq.ReceiveCompleted += mq_ReceiveCompleted;

            for (int i = 0; i < 10000; ++i)
                mq.Send(i);

            Console.WriteLine("Begin Receive...");
            mq.BeginReceive();

            Console.WriteLine("Press ENTER to exit loop");
            Console.ReadLine();

            Console.WriteLine("Closing...");

            mq.Close();
        }

        Console.WriteLine("Waiting...");
        idleWH.Wait();

        Console.WriteLine("Press ENTER (ex)");
        //Console.ReadLine();
    }

    static void mq_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
    {
        try
        {
            var msg = mq.EndReceive(e.AsyncResult);
            Console.Title = msg.Body.ToString();

            // Receive next message
            mq.BeginReceive();
        }
        catch (Exception ex)
        {
            idleWH.Set();
            return;
        }
    }
}
4

3 に答える 3

4

どうやってこれを機能させたのかよくわかりません。イベントで MessageQueue.EndReceive() を呼び出す必要があります。そのメソッドだけが例外をスローできます。ReceiveCompleted イベントの MSDN サンプル コードを確認してください。そして、診断不能な失敗を引き起こすだけの例外をキャッチしないでください。キューを破棄するときに取得する特定の例外、ObjectDisposedException をキャッチします。

于 2011-03-30T13:05:27.103 に答える
1

これを機能させる唯一の方法は、トランザクションキューを使用することでした。非トランザクションキューは、これに対して脆弱であるように見えます。答えではありませんが、これを見つけた人に私ができる最善のアドバイスです。

于 2013-03-11T13:11:43.713 に答える
0
    private static volatile bool _shouldStop = false;

。。。

            _shouldStop = true;
            mq.Close();

。。。

        try
        {
            var msg = mq.EndReceive(e.AsyncResult);

            if ( _shouldStop)
            {
                idleWH.Set();
                return;
            }

            mq.BeginReceive();
        }

。。。

于 2012-05-03T12:34:22.933 に答える