首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >.NET异步消息队列

.NET异步消息队列
EN

Stack Overflow用户
提问于 2011-03-30 20:07:18
回答 3查看 7.3K关注 0票数 5

我不明白哪里出了问题。基本上,我有一个从消息队列接收并处理消息的程序。程序可以在任何时候停止,在这种情况下,消息循环在程序退出之前完成了它正在做的事情。我试着用下面的代码来实现这一点:

代码语言:javascript
运行
复制
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)应该抛出异常。难道不是这样吗?如果没有,我还能如何安全地退出消息循环?

谢谢

更新:

下面是一个完整的示例(假设队列存在)

代码语言:javascript
运行
复制
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;
        }
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-03-11 21:11:44

我能让它工作的唯一方法是使用事务性队列。任何非事务性队列似乎都容易受到此问题的影响。不是一个答案,但我能给任何找到这个的人最好的建议。

票数 1
EN

Stack Overflow用户

发布于 2011-03-30 21:05:27

我根本不知道你是怎么做到的。您必须在该事件中调用MessageQueue.EndReceive()。只有该方法才能抛出异常。查看ReceiveCompleted事件的MSDN示例代码。并且不要捕获异常,这只会导致无法诊断的故障。捕获在处理队列时获得的特定异常ObjectDisposedException。

票数 4
EN

Stack Overflow用户

发布于 2012-05-03 20:34:23

代码语言:javascript
运行
复制
    private static volatile bool _shouldStop = false;

。。。

代码语言:javascript
运行
复制
            _shouldStop = true;
            mq.Close();

。。。

代码语言:javascript
运行
复制
        try
        {
            var msg = mq.EndReceive(e.AsyncResult);

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

            mq.BeginReceive();
        }

。。。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5486058

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档