开发者

Windows Service to regularly spawn a thread up to a maximum

开发者 https://www.devze.com 2023-03-24 06:59 出处:网络
I have read hundreds of pages and employed so many samples by now that I am completely confused.Most examples seems to target the following:

I have read hundreds of pages and employed so many samples by now that I am completely confused. Most examples seems to target the following:

  • Have a timer spawn a new thread that will do some work, with infinite threads
  • Spawn a specific number of threads, each with a timer that does something
  • On a regular basis do some work

What I am trying to accomplish is:

  • Have a timer running to regularly spawn a thread
  • This thread may or may not take longer than the timer-tick
  • Have a limit to how many threads can be spawned
  • When a thread finishes, give back the thread so that it can be use again
  • Work in each thread i开发者_开发技巧s independent of each-other, and can run in async (it doesn't really matter)

As an analogy, I want my application to work like a fishing boat with 10 fishing lines. At the start you cast one out (on demand), then another and so on. At any given time there can be from 0 to 10 fishing lines in the water. Whenever a fish is caught the line gets pulled up and is ready to be cast again (if there is the demand to).

It sounds like I should be using a ThreadPool? I was also think that to keep it simple I should spawn a thread, and if there is no work, return it immediately (i.e. select count from some table and if count is 0, return the thread), instead of trying to intelligently figure out if I need to spawn because there is a need.

In general, when the system is quiet, it will constantly be spawning one thread, see that there's no work and then return, but during busy times, the threads will probably be used up to the limit, whereby the system will just keep on failing to spawn new threads until one or more is returned again when they're finished.

I have tried System.Threading and Semaphores and WaitHandles but it all gets terribly confusing. I have no code to show yet, as I keep on deleting and starting again, with a different approach. Any help would be appreciated.

I develop in C# 2010.


I've gotten something like this working before using the threadpool and a timer:

public class MaxThreadCountWorker : IDisposable
{
    private readonly int _maxThreadCount;
    private readonly int _tickIntervalMilliseconds;
    private readonly Action _periodicWork;
    private readonly System.Threading.Timer _timer;
    private int _currentActiveCount;

    public MaxThreadCountWorker(int maxThreadCount, int tickIntervalMilliseconds, Action periodicWork)
    {
        _maxThreadCount = maxThreadCount;
        _tickIntervalMilliseconds = tickIntervalMilliseconds;
        _periodicWork = periodicWork;
        _timer = new System.Threading.Timer(_ => OnTick(), null, Timeout.Infinite, Timeout.Infinite);
        _currentActiveCount = 0;
    }

    public void Start()
    {
        _timer.Change(0, _tickIntervalMilliseconds);
    }

    public void Stop()
    {
        _timer.Change(Timeout.Infinite, Timeout.Infinite);
    }

    private void DoWork()
    {
        try
        {
            _periodicWork.Invoke();
        }
        finally
        {
            Interlocked.Decrement(ref _currentActiveCount);
        }
    }
    private void OnTick()
    {
        _timer.Change(Timeout.Infinite, Timeout.Infinite);
        try
        {
            if (_currentActiveCount >= _maxThreadCount) return;

            Interlocked.Increment(ref _currentActiveCount);
            ThreadPool.QueueUserWorkItem(_ => DoWork());
        }
        finally
        {
            _timer.Change(_tickIntervalMilliseconds, _tickIntervalMilliseconds);
        }
    }

    public void Dispose()
    {
        _timer.Dispose();
    }
} 

class Program
{
    private static object _lockObject = new object();
    private static int _runningTasks = 0;

    private static void PrintToConsole()
    {
        lock (_lockObject)
        {
            _runningTasks += 1;
        }
        try
        {
            Console.WriteLine("Starting work. Total active: {0}", _runningTasks);
            var r = new Random();
            System.Threading.Thread.Sleep(r.Next(3500));                
        } finally
        {
            lock (_lockObject)
            {
                _runningTasks -= 1;
            }                
        }
    }
    static void Main(string[] args)
    {
        using (var w = new MaxThreadCountWorker(3, 150, PrintToConsole))
        {
            w.Start();
            Console.ReadKey();
        }
    }
}


I think that you should use the builtin ThreadPool instead of inventing your own. The situations you are describing in the question are part of the complexity required to handle in a property implemented threadpool. Instead of doing that yourself I think that you can gain a lot by using an existing one (unless you are doing this to learn how thread pools work).

To use the builtin thread pool, you should call TreadPool.QueueUserWorkItem() in the event handler for the timer tick.


Threadpool is your answer. The real question is whether you need any feedback from the thread. If not, as seems to be the case, kick of threads in a threadpool, which will manage the limit on the number of threads. And then just continue, dealing with the timer ticks as a sleep process.

If you need anything back then the processing becomes far more complex.

And yes, kick off the thread, and let it decide whether there is any work to do. In this scenario, this makes perfect sense, and there is no value to checking whether you need to kick anything off.

0

精彩评论

暂无评论...
验证码 换一张
取 消