Надежный метод отслеживания неудачных работников с Threadpool

StackOverflow https://stackoverflow.com/questions/2184546

Вопрос

Я ищу хороший метод отслеживания (подсчета). Какие работники не удались прийти к очереди с ThreadPool и используя WATHANDLE.WATALL () для всех потоков для завершения.

Блокируется счетчик хорошей техникой или есть ли более надежная стратегия?

Это было полезно?

Решение

Хорошо, вот подход, который вы могли бы взять. Я инкапсулировал данные, которые мы хотим отслеживать в классе TrackedWorkers. Отказ На этом классе есть конструктор, который позволяет вам установить, сколько работников будет работать. Затем рабочие запускаются с использованием LaunchWorkers который требует делегата, который ест object и возвращает А. bool. Отказ То object представляет вход к работнику и bool представляет успех или неудачу в зависимости от true или false Быть возвращающимся значением соответственно.

Так что в основном мы у нас есть массив для отслеживания работника. Мы запускаем рабочие и устанавливаем статус, соответствующий этому работнику в зависимости от возвращаемого значения от работника. Когда работник возвращается, мы устанавливаем AutoResetEvent а также WaitHandle.WaitAll для всех AutoResetEvents быть установленным.

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

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

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

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

class TrackedWorkers {
    class WorkerState {
        public object Input { get; private set; }
        public int ID { get; private set; }
        public Func<object, bool> Func { get; private set; }
        public WorkerState(Func<object, bool> func, object input, int id) {
            Func = func;
            Input = input;
            ID = id;
        }
    }

    AutoResetEvent[] events;
    bool[] statuses;
    bool _workComplete;
    int _number;

    public TrackedWorkers(int number) {
        if (number <= 0 || number > 64) {
            throw new ArgumentOutOfRangeException(
                "number",
                "number must be positive and at most 64"
            );
        }
        this._number = number;
        events = new AutoResetEvent[number];
        statuses = new bool[number];
        _workComplete = false;
    }

    void Initialize() {
        _workComplete = false;
        for (int i = 0; i < _number; i++) {
            events[i] = new AutoResetEvent(false);
            statuses[i] = true;
        }
    }

    void DoWork(object state) {
        WorkerState ws = (WorkerState)state;
        statuses[ws.ID] = ws.Func(ws.Input);
        events[ws.ID].Set();
    }

    public void LaunchWorkers(Func<object, bool> func, object[] inputs) {
        Initialize();
        for (int i = 0; i < _number; i++) {
            WorkerState ws = new WorkerState(func, inputs[i], i);
            ThreadPool.QueueUserWorkItem(this.DoWork, ws);
        }
        WaitHandle.WaitAll(events);
        _workComplete = true;
    }

    void ThrowIfWorkIsNotDone() {
        if (!_workComplete) {
            throw new InvalidOperationException("work not complete");
        }
    }

    public bool GetWorkerStatus(int i) {
        ThrowIfWorkIsNotDone();
        return statuses[i];
    }

    public IEnumerable<int> SuccessfulWorkers {
        get {
            return WorkersWhere(b => b);
        }
    }

    public IEnumerable<int> FailedWorkers {
        get {
            return WorkersWhere(b => !b);
        }
    }

    IEnumerable<int> WorkersWhere(Predicate<bool> predicate) {
        ThrowIfWorkIsNotDone();
        for (int i = 0; i < _number; i++) {
            if (predicate(statuses[i])) {
                yield return i;
            }
        }
    }
}

Использование образца:

class Program {
    static Random rg = new Random();
    static object lockObject = new object();
    static void Main(string[] args) {
        int count = 64;
        Pair[] pairs = new Pair[count];
        for(int i = 0; i < count; i++) {
            pairs[i] = new Pair(i, 2 * i);
        }
        TrackedWorkers workers = new TrackedWorkers(count);
        workers.LaunchWorkers(SleepAndAdd, pairs.Cast<object>().ToArray());
        Console.WriteLine(
            "Number successful: {0}",
            workers.SuccessfulWorkers.Count()
        );
        Console.WriteLine(
            "Number failed: {0}",
            workers.FailedWorkers.Count()
        );
    }
    static bool SleepAndAdd(object o) {
        Pair pair = (Pair)o;
        int timeout;
        double d;
        lock (lockObject) {
            timeout = rg.Next(1000);
            d = rg.NextDouble();
        }
        Thread.Sleep(timeout);
        bool success = d < 0.5;
        if (success) {
            Console.WriteLine(pair.First + pair.Second);
        }
        return (success);

    }
}

Вышеуказанная программа будет запущена шестьдесят четыре потока. То iТема имеет задачу добавления чисел i а также 2 * i и печатать результат к консоли. Однако я добавил случайное количество сна (менее одного секунды), чтобы имитировать жизненно возможностей, и я переворачиваю монету, чтобы определить успех или отказ нити. Те, которые преуспевают на распечатать сумму, с которыми они были поручены и вернуться true. Отказ Те, которые терпят неудачу ничего и возвращают false.

Здесь я использовал

struct Pair {
    public int First { get; private set; }
    public int Second { get; private set; }
    public Pair(int first, int second) : this() {
        this.First = first;
        this.Second = second;
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top