Thursday, June 17, 2010

Thread safety

If you are developing a multi threaded application. Make sure you code is thread safe. For better performance try to protect only the resource being accessed for reading or writing across threads and some lines of code.

C#- Make sure the mutex, monito or semaphore, if used, are released properly.

Note: A semaphore with a capacity of one is similar to mutex or lock. Semaphore is thread-agnostic because it has no owner. Any thread can call release a semaphore, but with lock and mutex, only the thread that acquired the resource can release it.


C# example- Below Logger class covers using lock and monitor, releasing monitor and protecting only the resource being shared across threads.
class Logger
{
    public string FilePath { get; set; }
    private StreamWriter m_objStreamWriter = null;
    private object m_objLocker;
    public Logger()
    {
        m_objLocker=new object();
        FilePath = @"d:\log.txt";
    }
    public bool Open()
    {
        bool blnStatus = false;
        try
        {
            m_objStreamWriter = new StreamWriter(FilePath, true);
            blnStatus = true;
        }
        catch (Exception objEx)
        {
            Console.WriteLine(objEx.StackTrace);
        }
        finally
        {
        }
        return blnStatus;
    }
    public bool Close()
    {
        bool blnStatus = false;
        try
        {
            if (m_objStreamWriter != null)
            {
                m_objStreamWriter.Close();
                blnStatus = true;
            }
        }
        catch (Exception objEx)
        {
            Console.WriteLine(objEx.StackTrace);
        }
        finally
        {
        }
        return blnStatus;
    }
    //make sure Open is called before calling WriteToFile
    //make sure Close is called once all logging is done
    public bool WriteToFile(string strMessage)
    {
        bool blnStatus = false;
        if (strMessage != string.Empty && strMessage != null)
        {
            try
            {
                lock (m_objLocker)
                {
                    if (m_objStreamWriter != null)
                    {
                        //logs only the time and not the date
                        m_objStreamWriter.WriteLine(
                            DateTime.Now.TimeOfDay
                            + " - "
                            + strMessage
                            );
                        blnStatus = true;
                    }

                }
            }
            catch (Exception objEx)
            {
                //use messagebox if winforms application
                Console.WriteLine(objEx.StackTrace);
            }
            finally
            {
            }
        }
        return blnStatus;
    }
    //make sure the StreamWriter is closed
    //make sure thr Monitor is exit
    public bool WriteToFile_Local(string strMessage)
    {
        bool blnStatus = false;
        StreamWriter objStreamWriter = null;
        if (strMessage != string.Empty && strMessage != null)
        {
            try
            {
                Monitor.Enter(m_objLocker);
                objStreamWriter = new StreamWriter(FilePath,
                    true);
                //logs only the time and not the date
                objStreamWriter.WriteLine(
                    DateTime.Now.TimeOfDay + " - " + strMessage
                    );
                objStreamWriter.Close();
                Monitor.Exit(m_objLocker);
                blnStatus = true;
            }
            catch (Exception objEx)
            {
                //use messagebox if winforms application
                Console.WriteLine(objEx.StackTrace);
                if (objStreamWriter != null)
                {
                   objStreamWriter.Close();
                }
                Monitor.Exit(m_objLocker);
            }
            finally
            {
            }
        }
        return blnStatus;
    }
    //exception has to be handled by the caller
    //can not be unit tested using UnitTestingTool class
    public void WriteToFile_Local_Using(string strMessage)
    {
        StreamWriter objStreamWriter = null;
        if (strMessage != string.Empty && strMessage != null)
        {
            //private member variable
            lock (m_objLocker)
            {
                using (objStreamWriter =
                    new StreamWriter(FilePath, true))
                {
                    //logs only the time and not the date
                    objStreamWriter.WriteLine(
                        DateTime.Now.TimeOfDay + " - " +
                        strMessage
                        );
                }
            }
        }
    }
}

Rule: Write thread safe code if your application is multi threaded.

Rule: Protecting only the resource being shared across threads or processes.

Rule: Releasing the mutex, monitor or semaphore if used.

No comments: