Search code examples
c#multithreadingsemaphore

Semaphore and SemaphoreSlim usage Best Practices


I have created a semaphore instance on top of this class

public static SemaphoreSlim _zReportSemaphore = new SemaphoreSlim(1, 500);

And somewhere in my code i need to retrieve and send some data.

while (_isRunning)
{
    try
    {
        xBsonDocument = null;
        //I think its very clear in this line...
        MongoDBDAO.xGetInstance().GetZReportData(ref xBsonDocument);

        foreach (BsonDocument item in xBsonDocument)
        {
            try
            {
                ThreadObject xThreadObject = new ThreadObject();
                xThreadObject.m_strTerminalId = item.GetValue("_id")["TERMINAL_ID"].ToString();
                xThreadObject.m_strZNo = item.GetValue("_id")["Z_NO"].ToString();

                m_xBuildAndSendZReportThread = 
                    new Thread(new ParameterizedThreadStart(vBuildAndSendZReport));
                m_xBuildAndSendZReportThread.Start(xThreadObject);
            }
            catch (Exception xException)
            {
                xException.TraceError();
                continue;
            }

            Thread.Sleep(m_litleStepQTime); 
        }
    }
    catch (Exception xException)
    {
        Thread.Sleep(m_bigStepQTime);
        Trace.vInsertError(xException);
        continue;
    }

    Thread.Sleep(m_iSleepTime);
}

This thread targeting to send files to ftp

        private void vBuildAndSendZReport(object prm_objParameters)
        {
            _zReportSemaphore.Wait();
            RetriveDataFromMongoAndSend();
            _zReportSemaphore.Release();
        }

In this structure; if i don't use a semaphore it has working great but sometimes thread count overloading the CPU or Memory usage and machine has been crushing.

1- How can i provide control over data usage (ballancing, isolating threads etc.) with this slim semaphore?

2- Can I use SemaphoreSlim for this type of job in production? What can be the advantages and disadvantages of using such a workflow organization like this? Does it improve performance? in my special case

3- Is there another alternative that will provide system resource management and will wrap up the technical exception management

Update: I asked this question during a job I did a long time ago. After solving the problem, I realized that I did not return.

In the above example, the report sending job was happening in the file sharing environment. Other solutions are possible, such as using a CDN.

The question was: Why should I use a thread if it can't keep me informed about what it's doing, if it doesn't tell me if it has had successful results? Why should I use SemaphoreSlim for example!?

yes, of course it can be done with async programming. but I didn't want to include this library in related environment. It had to be. I'm sure this situation is needed in many codes.

my solution was this: I eliminated the possibility of the exception in the code that was throwing the exception. so i synced the conflict with the thread outside the app. I made something like a threadpool. It worked flawlessly as a consumer. I did this by setting up a custom timing mechanism.

Regardless, I still agree. A thread should be set up to carry information about the job it is doing. I'm not talking about writing a Mutex object in between. Thread itself can carry this information.

By the way, I gave points to those who answered. Because they made the right comments according the question.


Solution

  • This is the first hit on Google for "Semaphore and SemaphoreSlim usage Best Practices", so I would like to add 1 remark:

    At least this code:

    semaphore.Wait();
    DoSomeThing();
    semaphore.Release();
    

    should be at the minimum:

    semaphore.Wait();
    try
    {
        DoSomeThing();
    }
    finally
    {
        semaphore.Release();
    }
    

    Or else you might end up NEVER releasing the semaphore again if an exception occurs in DoSomeThing().

    And in async programming, consider using:

    await semaphore.WaitAsync();