none
Muti threading issue: .NET 2.0 Runtime Error kernel32.dll fault RRS feed

  • General discussion

  • I recently ran into a rather difficult bug and could not find any information about it.  I found a solution to my problem and decided to post here in the hopes that somebody googling for the same issue will find it....

     

    Event Type: Error
    Event Source: .NET Runtime 2.0 Error Reporting
    Event Category: None
    Event ID: 1000
    Description:
    Faulting application clientemail.service.exe, version 1.0.0.1, stamp 481740c1, faulting module kernel32.dll, version 5.2.3790.2919, stamp 4626487f, debug? 0, fault address 0x00015e02.

     

    this error happened in a windows service running under the NETWORK SERVICE account on windows server 2003 version 5.2 (build 3790.srv03_sp1_gdr.070304-2232 : Service Pack 1)

     

    I don't pretend to know the gory details of how & why, but I did find a work-around in my case.  The issue turned out to be that I was creating a delegate on a thread and then invoking it on another thread after the first thread had terminated.  The following code exhibited the problem:

     

     

    Code Snippet

    using System;
    using System.ServiceProcess;
    using System.Threading;
    using ClientEmail.log4net;

    namespace ClientEmail.Service
    {
        public class ClientEmailService : ServiceBase
        {
            ClientEmailServiceHandler svc;
            ILog log;
            Thread worker;
            volatile bool stopping;
            volatile bool running;
            Thread stopMonitor;

            public ClientEmailService()
            {
                log = LogManager.GetLogger(typeof(ClientEmailService));
                InitializeComponent();
            }

            protected override void OnStart(string[] args)
            {
                try
                {
                    log.Notice("ClientEmail service starting.");
                    svc = new ClientEmailServiceHandler();
                    svc.ExchangeError += new EventHandler<ErrorEventArgs>(svc_ExchangeError);
                    svc.Mailer.Error += new EventHandler<MailerEventArgs>(svc_MailerError);
                    svc.ProcessingError += new EventHandler<ErrorEventArgs>(svc_ProcessingError);
                    worker = new Thread(new ThreadStart(Loop));
                    stopMonitor = new Thread(new ThreadStart(() =>
                    {
                        while (running)
                        {
                            try
                            {
                                Thread.Sleep(1000);
                            }
                            catch { }
                        }
                        log.Debug("Monitor thread is stopping execution..");
                        if (!stopping)
                            this.Stop();
                        Thread.CurrentThread.Abort();
                    }));
                    running = true;
                    worker.Start();
                    stopMonitor.Start();
                }
                catch (Exception ex)
                {
                    log.Error("Error starting ClientEmailService", ex);
                    this.Stop();
                }
            }

            void Loop()
            {
                try
                {
                    while (running)
                    {
                        svc.LoopProc();
                        try
                        {
                            Thread.Sleep(30000);
                        }
                        catch { }
                        log.Verbose("ClientEmail service entering active state.");
                    }
                    log.Notice("ClientEmail worker thread exiting");
                }
                catch (Exception ex)
                {
                    log.Error("Unexpected exception.  Terminating service.", ex);
                }
                finally
                {
                    running = false;
                    Thread.CurrentThread.Abort();
                }
            }

            void svc_ProcessingError(object sender, ErrorEventArgs e)
            {
                log.Error("Error processing message.", e.Error);
            }

            void svc_MailerError(object sender, MailerErrorEventArgs e)
            {
                log.Error("Error sending message: " + e.Message.ToString(), e.Error);
            }

            void svc_ExchangeError(object sender, ErrorEventArgs e)
            {
                log.Error("Error communicating with exchange", e.Error);
            }

            protected override void OnStop()
            {
                try
                {
                    stopping = true;
                    running = false;
                    log.Notice("ClientEmail service is shutting down");
                    if (worker != null)
                    {
                        worker.Interrupt();
                        if (!worker.Join(31000))
                        {
                            log.Warn("Worker thread did not stop!");
                            if ((worker.ThreadState & System.Threading.ThreadState.Running) == System.Threading.ThreadState.Running)
                                worker.Abort();
                        }
                    }
                    if (svc != null)
                        svc.Dispose();
                    svc = null;
                    this.ExitCode = 0;
                    log.Notice("Stop was successful");
                }
                catch (Exception ex)
                {
                    log.Error("Error stopping ClientEmail service", ex);
                    this.ExitCode = 1;
                }
            }

            private void InitializeComponent()
            {
                //
                // ClientEmailService
                //
                this.ServiceName = "ClientEmail";

            }
        }
    }

     

     

    In the above code, ClientEmailServiceHandler is a class that does all the real work and ILog is a synchronized wrapper around the log4net framework.  When svc.LoopProc() was invoked on line 65, it would eventually trigger the svc.Mailer.Error event and that is when the kernel32.dll fault would occurr.

     

    In the end I had to remove the event handlers from the service class.  The error handling logic was moved into the ClientEmailServiceHandler class and everything works fine.

    Tuesday, April 29, 2008 5:42 PM

All replies

  • Can't be it, a delegate instance has no thread affinity.  It will run on the thread that invoked it, not on the thread that created it.  It's not clear from the code what else it might be.  
    Wednesday, April 30, 2008 1:35 AM
    Moderator