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 回答