Hamit YILDIRIM
Hamit YILDIRIM

Reputation: 4549

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.

Upvotes: 1

Views: 6025

Answers (2)

Geert
Geert

Reputation: 550

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();

Upvotes: 7

Peter Duniho
Peter Duniho

Reputation: 70701

Is there any event when semaphore ends its all threads

No. It's not even clear what that might mean. For example, what do you want to happen if, due to thread-scheduling issues, you have just one running thread in the semaphore at the moment, and that thread completes, releasing the semaphore, before one or more other threads even get to try to acquire the semaphore?

The semaphore has no way to detect this condition as different from every thread being done.

If you want to know when some collection of asynchronous operations has completed, you'll need to wait on that specifically. You have a number of options in .NET, including:

  1. Call Thread.Join() on all of the thread objects you've started.
  2. Use Task to run your asynchronous tasks instead of Thread, and use Task.WhenAll() (or less preferably, Task.WaitAll()) to wait for them to complete.
  3. Use CountdownEvent. Call AddCount() for each task you start, have each task call Signal() when it's done, and then wait on the CountdownEvent.


By the way, the code you posted is suspect in other ways:

  1. Why are you specifying a maximum count for the SemaphoreSlim, and why is this maximum not the same as your initial count? Do you actually expect to call Release() more often than you call Wait()?
  2. Code that calls Thread.Sleep() is often incorrect. It's not clear why you are doing that, but it's likely there are better ways to solve whatever issue you're trying to address with those calls.

Without a good Minimal, Complete, and Verifiable example, I can't say for sure that those things are wrong. But there's a low likelihood of them being right. :)

Upvotes: 2

Related Questions