Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 一种利用ThreadPool跟踪失败工人的鲁棒方法_C#_.net_Threadpool_Waithandle - Fatal编程技术网

C# 一种利用ThreadPool跟踪失败工人的鲁棒方法

C# 一种利用ThreadPool跟踪失败工人的鲁棒方法,c#,.net,threadpool,waithandle,C#,.net,Threadpool,Waithandle,我正在寻找一种很好的方法来跟踪(计算)当使用线程池排队并使用WaitHandle.WaitAll()让所有线程完成时,哪些工作线程失败了 联锁计数器是一种好技术还是有一种更稳健的策略 好的,这里有一个方法,你可以采取。我已经将我们要跟踪的数据封装到一个类中TrackedWorkers。这个类上有一个构造函数,可以让您设置将有多少工人在工作。然后,使用LaunchWorkers启动worker,这需要一个委托,该委托吃掉一个对象,并返回一个bool。对象表示工作人员的输入,bool表示成功或失败,

我正在寻找一种很好的方法来跟踪(计算)当使用线程池排队并使用WaitHandle.WaitAll()让所有线程完成时,哪些工作线程失败了


联锁计数器是一种好技术还是有一种更稳健的策略

好的,这里有一个方法,你可以采取。我已经将我们要跟踪的数据封装到一个类中
TrackedWorkers
。这个类上有一个构造函数,可以让您设置将有多少工人在工作。然后,使用
LaunchWorkers
启动worker,这需要一个委托,该委托吃掉一个
对象
,并返回一个
bool
对象
表示工作人员的输入,
bool
表示成功或失败,这分别取决于
true
false
作为返回值

所以基本上我们做的是,我们有一个数组来跟踪工作状态。我们启动worker并根据worker的返回值设置对应于该worker的状态。当工作人员返回时,我们为所有要设置的
AutoResetEvent
设置
AutoResetEvent
WaitHandle.WaitAll

请注意,有一个嵌套类用于跟踪工作人员应该执行的工作(委托)、该工作的输入以及用于设置与该线程对应的状态的
AutoResetEvent

请非常小心地注意,一旦工作完成,我们就不会引用工作委托
func
,也不会引用
输入。这一点很重要,这样我们就不会意外地阻止垃圾收集

有一些方法可以获取特定工作人员的状态,以及成功工作人员的所有索引和失败工作人员的所有索引

最后一个注意事项:我不认为这个代码生产准备好了。这只是我将采取的方法的一个草图。您需要注意添加测试、异常处理和其他此类细节

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

您如何设想报告其状态的线程?如果他们只是将
bool
设置为
true
false
可以吗?我想排队的方法会有一个静态计数器,我没有遵循;计数器似乎只用于告诉您有多少工人成功或失败,而不用于告诉您哪些工人成功或失败。我遗漏了什么?对不起,是的,我只需要一个CPU t,虽然这对logarghh iPhone自动更正很有用,@Jason我需要计数,但也失败了,这对记录+5有好处。我想我可能把这个问题说得很糟糕,否则我会得到更多的答复。一个小改动是委托,而不是lambdaI。我将把它重新表述为lambda很好。事件是一个坏的选择吗?我理解WorkItem的限制,但您在threadpool中放入的项目数量是否有限制?对不起,如果我把这个改成另外两个questions@Chris学生:这个问题有点不清楚;你留下了一些未说明的东西。问问题时尽量精确,当然不要迂腐,这很有帮助。也就是说,我们在对你的问题的评论中澄清了一些事情。你所说的“事件是一个糟糕的选择”是什么意思?作为一种信号机制?至于限制,可以等待的
AutoResetEvent
的数量是有限制的。如果您需要更多线程,则必须进行一些工作,将它们拆分到多个
AutoResetEvent
集合中。事件用于向UI发回事件发生的信号是,当您将10000个项目排入线程池时会发生什么情况,这一定是队列中某个地方的8000个对象。我可能不会使用这个精确的解决方案,但它已经足够接近了
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);

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