Question

Je ne comprends pas où cela va mal. Fondamentalement, j'ai un programme qui reçoit d'une file d'attente de message et traite les messages. Le programme peut être arrêté à tout moment, auquel cas la boucle de messages a terminé ce qu'il fait avant la sortie du programme. J'essaie d'accomplir cela avec le code suivant:

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();
}

Espérons que l'apparence apparente, la méthode d'arrêt dispose de la file d'attente de messages, puis attend que la poignée d'attente inactive soit définie (ce qui devrait se produire à mesure que l'événement reçus est appelé lors de la disposition, mais la propriété E.MESSAGE devrait sauf ).

Cependant, la boucle de message continue! J'ai disposé la file d'attente de messages, mais elle réussit toujours à lire à partir de celui-ci et que le gestionnaire d'exception n'est pas invoqué, ce qui signifie que l'idle.Wait ligne attend pour toujours.

Ma compréhension est que la mise au rebut d'une file d'attente de message devrait finaliser tout en attente et invoquer l'événement, mais le E.MESSAGE (ou Q.Endeceive) devrait organiser une exception. Ce n'est pas le cas? Sinon, comment puis-je sortir en toute sécurité de ma boucle de message?

merci

mise à jour:

Voici un exemple complet (suppose que la file d'attente existe)

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;
        }
    }
}

Était-ce utile?

La solution 2

La seule façon de gagner ce travail était avec une file d'attente transactionnelle.Toute file d'attente non transactionnelle semble être vulnérable à cela.Pas une réponse, mais le meilleur conseil que je puisse donner à quiconque en trouvant cela.

Autres conseils

Pas tout à fait sûr de la façon dont vous avez fait ce travail.Vous doit appelersqueue.endreceive () dans l'événement.Seule cette méthode peut jeter l'exception.Examinez le code de l'échantillon MSDN pour l'événement reçus.Et ne pas attraper une exception, cela provoque juste une défaillance non diagnostiquable.Attrapez l'exception spécifique que vous obtenez lorsque vous disposez de la file d'attente, 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();
        }

...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top