Счетчик запущенных Task

118
31 октября 2019, 07:00

В своем приложении использую много фоновых задач.

Нужен счетчик активных задач. Для того чтобы корректно закрывать приложение дождавшись нулевого значения. Использую вместо Task.Factory.StartNew( ... ); TasksHub.StartNewTask( ... );

public static class TasksHub
{
    private static int tasksActive = 0;
    public static event EventHandler TasksActiveIsUpdated;
    public static int TasksActive
    {
        get
        {
            return tasksActive;
        }
        set
        {
            tasksActive = value;
            OnTasksActiveIsUpdated(null);
        }
    }
    public static void OnTasksActiveIsUpdated(EventArgs e)
    {
        EventHandler handler = TasksActiveIsUpdated;
        if (handler != null)
        {
            Application.Current.Dispatcher.Invoke(() => { handler(null, e); });
            //handler(null, e);
        }
    }

    public static Task StartNewTask(Action action)
    {
        lock (new object()) TasksActive++;
        return Task.Factory.StartNew(() => {
            action();
            lock (new object()) TasksActive--;
        });
    }
    public static Task<T> StartNewTask<T>(Func<T> function)
    {
        lock (new object()) TasksActive++;
        return Task.Factory.StartNew(() => {
            var result = function();
            lock (new object()) TasksActive--;
            return result;
        });
    }
}

Проблема в следующем. Счетчик TasksActive долгий период времени может иметь значение 1. Это понятно какая-то задача подвисает. Но TasksActive принимает и отрицательные значения. Каким образом TasksActive становится отрицательным я не могу понять.

Answer 1

Осмелюсь предложить такой вариант

static class TasksHub
{
    private static bool _closed = false;
    private static CountdownEvent _countdownEvent = new CountdownEvent(1);
    public static Task StartNewTask(Action action)
    {
        _countdownEvent.AddCount();
        try {
            return Task.Factory.StartNew(() => {
                try {
                    action();
                }
                finally {
                    _countdownEvent.Signal();
                }
            });
        }
        catch {
            // если StartNew бросит исключение надо обязательно уменьшить счетчик
            _countdownEvent.Signal();
            throw;
        }
    }
    public static Task<T> StartNewTask<T>(Func<T> function)
    {
        _countdownEvent.AddCount();
        try {
            return Task.Factory.StartNew(() => {
                try {
                    return function();
                }
                finally {
                    _countdownEvent.Signal();
                }
            });
        }
        catch {
            // если StartNew бросит исключение надо обязательно уменьшить счетчик
            _countdownEvent.Signal();
            throw;
        }
    }
    public static int TasksCount
    {
        get {
            return _countdownEvent.CurrentCount - (!_closed ? 1 : 0);
        }
    }
    public static void CloseAndWait()
    {
        CloseAndWait(-1);
    }
    public static bool CloseAndWait(int millisecondsTimeout)
    {
        if (!_closed) {
            _countdownEvent.Signal();
            _closed = true;
        }
        return _countdownEvent.Wait(millisecondsTimeout);
    }
}
class Program
{
    static void Main(string[] args)
    {
        TasksHub.StartNewTask(() => {
            Thread.Sleep(5000);
        });
        TasksHub.StartNewTask(() => {
            Thread.Sleep(1000);
        });
        var b1 = TasksHub.CloseAndWait(10);
        TasksHub.CloseAndWait();
    }
}
Answer 2

Спасибо за помощь. В итоге переделал в следующий вид.

public static class TasksHub
{
    private static int tasksActive = 0;
    public static event EventHandler TasksActiveIsUpdated;
    public static int TasksActive
    {
        get
        {
            return tasksActive;
        }
    }
    public static void OnTasksActiveIsUpdated(EventArgs e)
    {
        EventHandler handler = TasksActiveIsUpdated;
        if (handler != null)
        {
            Application.Current.Dispatcher.Invoke(() => { handler(null, e); });
        }
    }
    private static void TasksActiveIncrement()
    {
        Interlocked.Increment(ref tasksActive);
        OnTasksActiveIsUpdated(null);
    }
    private static void TasksActiveDecrement()
    {
        Interlocked.Decrement(ref tasksActive);
        OnTasksActiveIsUpdated(null);
    }

    public static int GetTasksActive()
    {
        return tasksActive;
    }
    public static Task StartNewTask(Action action)
    {
        int startTimestamp = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        TasksActiveIncrement();
        return Task.Factory.StartNew(() => {
            action();
            TasksActiveDecrement();
        });
    }
    public static Task<T> StartNewTask<T>(Func<T> function)
    {
        int startTimestamp = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        TasksActiveIncrement();
        return Task.Factory.StartNew(() => {
            var result = function();
            TasksActiveDecrement();
            return result;
        });
    }
}
READ ALSO
NAudio - Mp3FileReader - медленный вывод аудио

NAudio - Mp3FileReader - медленный вывод аудио

Я преобразую входящий поток wav в mp3 через Lame этой функцией:

149
Не могу разобрать XML

Не могу разобрать XML

Получаю вот такой ответ от сайта в формате xml

128
Что возвращает include/require?

Что возвращает include/require?

Содержимое файла canChangeStatusphp:

134