Challenging Multithread Question 500points

I am creating a Multithreaded C# Application.  The application will query a database for "jobs" to execute.  If it finds available jobs it will create a new "Job Object" (based on parameters supplied from the dataset returned from the query) and a  fresh worker thread for each job to be run.  This all works great.  I know that when the method (doSomeWork in the below example)  that the new thread calls exits the thread terminates.
Thread workthread = new Thread(new ThreadStart(doSomeWork));

What I need to accomplish is keeping track of all currently running threads.  When the thread is created it will increment an int variable, and decrement that variable when the thread exits.  I would also like to uniquely identify each thread.  So I can have, say a list box on a Winform showing currently executng threads.  So, essentially how do I monitor/track/label existing threads?

500 Points for some help.
LVL 3
mandalorian4Asked:
Who is Participating?
 
boblahConnect With a Mentor Commented:
Hi mandalorian4,

Create a singleton object (Design patterns, GoF) - basically an object that has a single instance that all the different threads can access.

Have methods for threads to register themselves with it, and notify it when they are finished. (be careful the finish call is robust, with error trapping and finally etc)

The front end can then interrogate the singleton for the current status.

Below is an example of a singleton I wrote once for a situation where various different threads were accessing a printer resource for which we only had five licenses - so only five threads at any one time could do the printing.

It should be reasonably clear how to modify it for your situation, although it does contain a bunch of stuff you don't need. Note the locking for the thread count etc. I guess you would add a collection to store references to the threads that register themselves with the singleton.

To get a reference to the instance of the singleton, use the following code:

            CrLicenseLock oCrLicenseLock = CrLicenseLock.GetInstance();

the class is as follows:

        private sealed class CrLicenseLock
        {
            private int mnLicenseCount = 0;
            private const int LICENSE_COUNT_MAX = 3;
            private const int TIMEOUT = 1000;
            private AutoResetEvent moARE = null;

            #region Constructor etc
            static readonly CrLicenseLock instance=new CrLicenseLock();
            /// <summary>
            /// the method could easily be converted to a property with only an accessor,
            /// with no impact on thread-safety or performance.
            /// </summary>
            /// <returns></returns>
            public static CrLicenseLock GetInstance()
            {
                return instance;
            }
            // Explicit static constructor to tell C# compiler
            // not to mark type as beforefieldinit
            static CrLicenseLock()
            {
            }
            public CrLicenseLock()
            {
                moARE = new AutoResetEvent(false);
            }
            #endregion

            #region External Methods
            #region LicenseGet
            /// <summary>
            /// should only be called from a try block, with a finally block containing the LicenseReturn
            /// would be improved by implementing a queuing system,
            /// would avoid numerous threads all hitting license count simultaneously
            /// however, only scaling issue, and if it were an issue
            /// the number of cr licenses would be woefully inadequate.
            /// </summary>
            /// <returns></returns>
            //
            public bool LicenseGet()
            {
                bool bReturn = false;
                bool bFirstTime = true;

                DateTime dtStart = DateTime.Now;

                do
                {
                    if(bFirstTime)
                        bFirstTime = false;
                    else
                    {
                        //all will clamour when signalled, but not big problem
                        moARE.WaitOne(TIMEOUT - DateTime.Now.Subtract(dtStart).Milliseconds, false);
                    }

                    lock(this)
                    {
                        if(mnLicenseCount < LICENSE_COUNT_MAX)
                        {
                            mnLicenseCount++;
                            bReturn = true;
                        }
                    }
                }while(bReturn == false && DateTime.Now.Subtract(dtStart).Milliseconds < TIMEOUT);

                return bReturn;
            }
            #endregion
            #region LicenseReturn
            public void LicenseReturn()
            {
                lock(this)
                {
                    mnLicenseCount--;
                }
                moARE.Set();
            }
            #endregion
            #endregion
        }


Cheers!
0
 
mandalorian4Author Commented:
boblah,

Thank you for the prompt response.  I will try to incorporate your solution shortly.  I noticed you used.

I am afraid I still do not understand how to identify a thread when multiple threads are created.  I see in my locals window a thread ID, but I do not see how to set or get the property.



Thank you.
0
 
ptmcompCommented:
AppDomain.GetCurrentThreadId() returns the unique id of the current thread.
You can assign a name to a thread.
To increment / decrement values threadsafe you can use the Interlocked.Decrement / Interlocked.Increment methods. (Evaluate the return value not the value in the variable)
0
 
ptmcompCommented:
BTW: You can not set the thread id. It's given by the system.
0
 
boblahCommented:
mandalorian4,

More details on creating a singleton

    /// <summary>
    /// Summary description for SingletonTest.
    /// This object works as a singleton
    /// for details of why this is the best way to do a proper, thread safe, lazy loaded singleton
    /// (one other way for full lazy loading, but slightly higher performance cost)
    /// see: http://www.yoda.arachsys.com/csharp/singleton.html
    /// sealed declaration is not strictly necessary, but might help optimisation
    /// </summary>
    public sealed class SingletonTest
    {
        public string CreateTime = "";

        #region Constructor etc
        private static readonly SingletonTest instance = new SingletonTest();
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static SingletonTest()
        {
        }
        public SingletonTest()
        {
            CreateTime = System.DateTime.Now.ToString();
        }
        /// <summary>
        /// the method could easily be converted to a property with only an accessor,
        /// with no impact on thread-safety or performance.
        /// </summary>
        /// <returns></returns>
        public static SingletonTest GetInstance()
        {
            return instance;
        }
        #endregion


    }
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.