简体   繁体   中英

Transparent code execution before and after Thread/Task/Action/

The point of all this is to run a separate Thread ( can be something similar: Task, Action ) and to log the "start" and the "end", preferably minimizing code impact (changes) and logging being transparent to the code, just using a different class .

Recently I decided to inherit from class System.Threading.Thread as a way to implement logging for things like "Thread x started." and "Thread x ended." to a file, for debugging. Since the class is sealed I used composition to add the Thread as a member and call respective function, accessors and all necessary. I had a simplistic idea of how to do it so I thought something like

namespace MyNamespace
{
    class Thread
    {
        private System.Threading.Thread thread;

        //wrap constructor properties methods...
        //...

        public void Start()
        {
                log(thread.name + " start.");
                thread.Start();
                log(thread.name + " end.");
        }

        //...
    }
}

Now after all this trouble of wrapping existing functionality (and using the new namespace instead of System.Threading)... this turned out to be bad since this call if I'm not mistaking is from the calling Thread and second the "end" does not log. The logging is mainly for debugging and having a non-volatile state of what happened.

EDIT:

Here's a simplified code using Ahmed's answer, which is good, and still ongoing issue is that if the SimulatedThread throws an exception the "Ending..." doesn't log for either "MainThread" or "CustomThread". If the CustomThread abnormally terminates, "Ending..." for "MainThread" and "CustomThread" should be recorded. ( The exception handling is not relevant ). "MainThread" should be bulletproof from "CustomThread".

Full implementation

using System;
using System.Security;
using System.Threading;

namespace CS_Tests_Console
{
    class Program
    {
        static void Main(string[] args)
        {
            Logger.Log("Starting...");
            try
            {
                Thread.CurrentThread.Name = "MainThread";
                CustomThread thread = new CustomThread(SimulateThread)
                    {
                        Name = "CustomThread",
                    };
                thread.Start();
                thread.Join();
            }
            catch (Exception ex)
            {
                Logger.Log("Cought exception:" + ex.ToString());
            }
            Logger.Log("Ending...");
        }

        private static void SimulateThread()
        {
            Logger.Log("Running...");
            Thread.Sleep(2000);
            throw new Exception("Test Exception");
        }
    }

    public static class Logger
    {
        public static void Log(String message)
        {
            if (Thread.CurrentThread.Name == null)
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " Thread.CurrentThread.Name is NULL -> " + message);
            }
            else
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " " + Thread.CurrentThread.Name + " -> " + message);
            }
        }
    }

    public class CustomThread
    {
        public Thread threadInstance { get; private set; }
        public CustomThread(ThreadStart threadStart)
        {
            threadInstance = new Thread(() =>
            {
                Logger.Log("Starting...");
                threadStart();
                Logger.Log("Ending...");
            });
        }

        public string Name { get { return threadInstance.Name; } set { threadInstance.Name = value; } }

        [SecuritySafeCritical]
        public void Join()
        {
            threadInstance.Join();
        }

        public void Start()
        {
            threadInstance.Start();
        }
    }
}

Encapsulate logging in the ThreadStart delegate:

public class Logger{
    public void Log(String message){
        Console.WriteLine(message);
    }
}

public class CustomThread {
    public Thread ThreadInst { get; private set; }
    public Logger logger = new Logger();
    public CustomThread(ThreadStart threadStart) {
        ThreadInst = new Thread(() =>
        {
            logger.Log(Thread.CurrentThread.Name + " Starting...");
            threadStart();
            logger.Log(Thread.CurrentThread.Name + " Ending...");
        });
    }
    public void Start() { ThreadInst.Start(); }
}
class Program
{

    static void Main(string[] args)
    {
        new CustomThread(() => Thread.Sleep(2000)).Start();
    }
}

Edit: Added catching and logging exceptions:

    public CustomThread(ThreadStart threadStart) {
        ThreadInst = new Thread(() =>
        {
            logger.Log(Thread.CurrentThread.Name + " Starting...");
            try {
                threadStart();
            } catch (Exception ex) {
                logger.Log("Error in thread" + Thread.CurrentThread.Name + " " + ex.Message);
            }
            logger.Log(Thread.CurrentThread.Name + " Ending...");
        });
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM