Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# .NET异步MSMQ_C#_.net_Asynchronous_Msmq_Beginreceive - Fatal编程技术网

C# .NET异步MSMQ

C# .NET异步MSMQ,c#,.net,asynchronous,msmq,beginreceive,C#,.net,Asynchronous,Msmq,Beginreceive,我不明白这是怎么回事。基本上,我有一个从消息队列接收消息并处理消息的程序。程序可以随时停止,在这种情况下,消息循环在程序退出之前完成了它正在做的事情。我正试图通过以下代码实现这一点: private MessageQueue q; private ManualResetEventSlim idle; public void Start() { idle = new ManualResetEventSlim(); q.ReceiveCompleted += this.Messag

我不明白这是怎么回事。基本上,我有一个从消息队列接收消息并处理消息的程序。程序可以随时停止,在这种情况下,消息循环在程序退出之前完成了它正在做的事情。我正试图通过以下代码实现这一点:

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)应该引发异常。不是这样吗?否则,我如何才能安全地退出消息循环

谢谢

更新:

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

类程序
{
静态消息队列;
静态手动复位idleWH;
静态void Main(字符串[]参数)
{
idleWH=新的手动重置事件slim();
控制台。写线(“打开…”);
使用(mq=newMessageQueue(@“\private$\test”))
{
mq.Formatter=newXMLMessageFormatter(新类型[]{typeof(int)});
mq.ReceiveCompleted+=mq_ReceiveCompleted;
对于(int i=0;i<10000;++i)
mq.Send(i);
Console.WriteLine(“开始接收…”);
mq.BeginReceive();
Console.WriteLine(“按ENTER键退出循环”);
Console.ReadLine();
控制台。写入线(“关闭…”);
mq.Close();
}
控制台。WriteLine(“等待…”);
idleWH.Wait();
控制台写入线(“按回车键(ex)”;
//Console.ReadLine();
}
静态无效mq_ReceiveCompleted(对象发送方,ReceiveCompletedEventArgs e)
{
尝试
{
var msg=mq.EndReceive(例如AsyncResult);
Console.Title=msg.Body.ToString();
//接收下一条消息
mq.BeginReceive();
}
捕获(例外情况除外)
{
idleWH.Set();
返回;
}
}
}

根本不太清楚您是如何做到这一点的。您必须在事件中调用MessageQueue.EndReceive()。只有该方法才能引发异常。查看ReceiveCompleted事件的MSDN示例代码。不要捕捉异常,这只会导致无法诊断的故障。捕获在处理队列时获得的特定异常ObjectDisposedException

    private static volatile bool _shouldStop = false;

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

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

            mq.BeginReceive();
        }

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

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

            mq.BeginReceive();
        }

我能让它工作的唯一方法是使用事务性队列。任何非事务性队列似乎都易受此攻击。不是答案,而是我能给任何人的最好建议。

只是好奇,为什么不公开一个?这将使您不必担心队列的管理和消息的读取,并且更加关注您的逻辑。这是一种竞争条件。mq_ReceiveCompleted与Dispose()同时执行,因此允许您接收在调用BeginReceive()时挂起的消息,或者可能是在调用BeginReceive()之后但在Dispose()完成之前到达的任何消息。你不能依赖于两个同时执行的操作的顺序。尽管如此,它确实有效。据我所知,Message属性的作用与q.EndReceive(e.AsyncResult)相同,事实上,如果我改为使用EndReceive方法,我会得到相同的结果-队列在被释放后将继续被使用。这是准确的,Message属性getter确实第一次调用EndReceive。把它擦掉。抓着稻草,我看不到MessageQueue构造函数。队列实际打开了吗?好的,示例在第一篇文章中。奇怪的是,如果队列是空的(并且填充一些测试数据的循环不在那里),那么示例将按预期工作-按ENTER键将导致事件处理程序执行except操作,程序将正确退出。似乎只有从队列接收到任何消息时才会发生这种情况。