Question

Je cherche une bonne méthode de suivi (comptage) dont les travailleurs ont échoué lorsque la file d'attente avec un Threadpool et en utilisant WaitHandle.WaitAll () pour tous les threads pour terminer.

est un compteur d'interverrouillage une bonne technique ou est-il une stratégie plus robuste?

Était-ce utile?

La solution

D'accord, voici une approche que vous pourriez prendre. J'ai les données encapsulé que nous voulons suivre dans une TrackedWorkers de classe. Il est un constructeur de cette classe qui vous permet de définir le nombre de travailleurs vont travailler. Ensuite, les travailleurs sont lancés à l'aide LaunchWorkers qui exige un délégué qui mange un object et retourne un bool. Le object représente l'entrée du travailleur et l'bool représente le succès ou l'échec selon true ou false étant la valeur de retour, respectivement.

Donc, fondamentalement, ce que nous faisons, nous avons un tableau de suivi de l'état des travailleurs. Nous lançons les travailleurs et définir le statut correspondant à ce travailleur en fonction de la valeur de retour du travailleur. Lorsque le travailleur retourne, nous avons mis un AutoResetEvent et WaitHandle.WaitAll pour tous les AutoResetEvents à définir.

Notez qu'il ya une classe imbriquée pour suivre les travaux (le délégué) le travailleur est censé faire, l'entrée à ce travail, et un ID utilisé pour définir le AutoResetEvent d'état correspondant à ce fil.

Notez très soigneusement que lorsque le travail est fait, nous ne sommes pas une référence sur le délégué de travail func ni à la input. Ceci est important pour que nous ne prévenons pas accidentellement des choses d'être des ordures collectées.

Il existe des méthodes pour obtenir le statut d'un travailleur en particulier, ainsi que tous les indices des travailleurs qui se sont succédés et tous les indices des travailleurs qui ont échoué.

Une dernière note: Je ne considère pas cette production de code prêt. Il est simplement un croquis de l'approche que je prendrais. Vous devez prendre soin d'ajouter les tests, la gestion des exceptions et d'autres détails.

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;
            }
        }
    }
}

Utilisation de l'échantillon:

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);

    }
}

Le programme ci-dessus va lancer soixante-quatre fils. Le fil ith a la tâche d'ajouter les numéros i et 2 * i et imprimer le résultat à la console. Cependant, j'ai ajouté une quantité aléatoire de sommeil (moins d'une seconde) pour simuler affairement et je feuillette une pièce de monnaie pour déterminer le succès ou l'échec du fil. Ceux qui réussissent imprimer la somme qu'ils ont été chargés et le retour true. Ceux qui ne rien d'impression et false de retour.

Ici, je l'ai utilisé

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;
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top