Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SemaphoreSlim with dynamic maxCount

I'm facing a problem where I need to limit the number of calls to another web server. It will vary because the server is shared and maybe it could have more or less capacity.

I was thinking about using SemaphoreSlim class, but there's no public property to change the max count.

Should I wrap my SemaphoreSlim class in another class that will handle the max count? Is there any better approach?

EDIT:

Here's what I'm trying:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Semaphore
{
class Program
{
    static SemaphoreSlim _sem = new SemaphoreSlim(10,10000);

    static void Main(string[] args)
    {
        int max = 15;

        for (int i = 1; i <= 50; i++)
        {
            new Thread(Enter).Start(new int[] { i, max});
        }

        Console.ReadLine();

        max = 11;

        for (int i = 1; i <= 50; i++)
        {
            new Thread(Enter).Start(new int[] { i, max });
        }
    }

    static void Enter(object param)
    {
        int[] arr = (int[])param;
        int id = arr[0];
        int max = arr[1];

        try
        {
            Console.WriteLine(_sem.CurrentCount);

            if (_sem.CurrentCount <= max)
                _sem.Release(1);
            else
            {
                _sem.Wait(1000);

                Console.WriteLine(id + " wants to enter");

                Thread.Sleep((1000 * id) / 2); // can be here at

                Console.WriteLine(id + " is in!"); // Only three threads

            }
        }
        catch(Exception ex)
        {
            Console.WriteLine("opps ", id);
            Console.WriteLine(ex.Message);
        }
        finally            
        {
            _sem.Release();
        }
    }
}
}

Questions:

1-_sem.Wait(1000) should cancel the execution of threads that will execute for more than 1000ms, wasn't it?

2-Did I got the idea of using Release / Wait?

like image 824
Thiago Custodio Avatar asked Jun 05 '14 18:06

Thiago Custodio


1 Answers

You can't change the max count, but you can create a SemaphoreSlim that has a very high maximum count, and reserve some of them. See this constructor.

So let's say that the absolute maximum number of concurrent calls is 100, but initially you want it to be 25. You initialize your semaphore:

SemaphoreSlim sem = new SemaphoreSlim(25, 100);

So 25 is the number of requests that can be serviced concurrently. You have reserved the other 75.

If you then want to increase the number allowed, just call Release(num). If you called Release(10), then the number would go to 35.

Now, if you want to reduce the number of available requests, you have to call WaitOne multiple times. For example, if you want to remove 10 from the available count:

for (var i = 0; i < 10; ++i)
{
    sem.WaitOne();
}

This has the potential of blocking until other clients release the semaphore. That is, if you allow 35 concurrent requests and you want to reduce it to 25, but there are already 35 clients with active requests, that WaitOne will block until a client calls Release, and the loop won't terminate until 10 clients release.

like image 114
Jim Mischel Avatar answered Sep 28 '22 16:09

Jim Mischel