Служба Windows регулярно порождает поток до максимума - PullRequest
2 голосов
/ 29 июля 2011

Я прочитал сотни страниц и использовал так много примеров, что я совершенно запутался. Большинство примеров, похоже, нацелены на следующее:

  • Имейте таймер, создающий новую нить, которая будет выполнять некоторую работу, с бесконечным нити
  • Создать определенное количество потоков, каждый с таймером, который делает что-то
  • Регулярно выполняйте работу

То, что я пытаюсь сделать, это:

  • Включите таймер для регулярного создания потока
  • Эта тема может занимать или не занимать больше времени, чем отметка таймера
  • Ограничить количество создаваемых потоков
  • Когда поток завершается, верните поток, чтобы его можно было использовать снова
  • Работа в каждом потоке не зависит друг от друга и может выполняться в асинхронном режиме (это не имеет значения)

В качестве аналогии я хочу, чтобы мое приложение работало как рыбацкая лодка с 10 лесками. В начале вы разыгрываете одну (по требованию), затем другую и так далее. В любой момент времени в воде может быть от 0 до 10 лесок. Всякий раз, когда рыба поймана, леска вытягивается и снова готова к броску (если есть потребность).

Похоже, я должен использовать ThreadPool? Я также думал, что для простоты я должен порождать поток, и если нет работы, немедленно вернуть его (т.е. выбрать счетчик из некоторой таблицы и, если счетчик равен 0, вернуть поток), вместо того, чтобы пытаться разумно выяснить если мне нужно порождать, потому что есть необходимость.

В общем, когда система работает тихо, она будет постоянно порождать один поток, видеть, что нет работы, а затем возвращаться, но в загруженное время потоки, вероятно, будут использоваться до предела, в результате чего система будет просто продолжайте отказывать в порождении новых потоков, пока один или несколько не будут возвращены снова, когда они закончат.

Я пробовал System.Threading, Semaphores и WaitHandles, но все это ужасно сбивает с толку. У меня пока нет кода для показа, так как я продолжаю удалять и начинать заново, используя другой подход. Любая помощь будет оценена.

Я развиваюсь в C # 2010.

Ответы [ 3 ]

2 голосов
/ 29 июля 2011

Я получил что-то вроде этого, прежде чем использовать пул потоков и таймер:

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();
        }
    }
}
0 голосов
/ 29 июля 2011

Threadpool - ваш ответ.Реальный вопрос в том, нужны ли вам какие-либо отзывы из ветки.Если нет, то, как кажется, имеет место выброс потоков в пуле потоков, который будет управлять ограничением количества потоков.А затем просто продолжайте, имея дело с таймерами таймера как сном.

Если вам что-то понадобится, тогда обработка становится намного более сложной.

И да, начните с потокаэто решает, есть ли какая работа, чтобы сделать.В этом сценарии это имеет смысл, и нет смысла проверять, нужно ли вам что-то начинать.

0 голосов
/ 29 июля 2011

Я думаю, что вы должны использовать встроенный ThreadPool вместо того, чтобы изобретать свой собственный. Ситуации, которые вы описываете в вопросе, являются частью сложности, необходимой для обработки в пуле потоков, реализуемом свойством. Вместо того, чтобы делать это самостоятельно, я думаю, что вы можете получить большую выгоду, используя существующую (если вы не делаете это, чтобы узнать, как работают пулы потоков).

Чтобы использовать встроенный пул потоков, вы должны вызвать TreadPool.QueueUserWorkItem() в обработчике событий для отметки таймера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...