ManualResetEvent 对象数组

Posted

技术标签:

【中文标题】ManualResetEvent 对象数组【英文标题】:Array of ManualResetEvent objects 【发布时间】:2017-02-09 07:34:46 【问题描述】:

这是我的故事:我有 wcf 服务。它接收有工作要做的请求。每个任务都插入阻塞队列。服务器将定期从此队列中获取项目并完成工作(在不同的线程中完全异步)。在我的“执行”服务中,我需要知道“我的”任务何时完成。像这样:

    public bool Do(int input)
    
        // 1. Add task to the BlockingCollection queue
        // 2. Block this thread from returning and observe/wait til my task is finished
        return true;
    

这是我的建议/解决方案:

    public bool Do(int input)
    
        // 1. Create a ManualResetEvent object
        // 2. Add this object to task
        // 3. Add task to the BlockingCollection queue
        // 4. Block this thread from returning - wait for ManualResetEvent object
        return true;
    

因此,ManualResetEvent 对象的数量将与要执行的任务一样多。我将真正拥有一组同步对象。这对我的问题有很好的解决方案吗?

或者在我的情况下有更好的同步类吗?像等待和脉搏?

感谢您的帮助,

我很抱歉标题。我不知道如何在标题中提出这个问题。

【问题讨论】:

为每个任务创建一个类State对象并创建一个List。将 time 和 id 等属性放入 State 以及线程对象中。 【参考方案1】:

你的计划很好,但是我建议不要占用一个专门的线程来等待工作完成。从new ManualResetEvent(false) 切换到new SemephoreSlim(0,1) 将允许您使用WaitAsync(),这将允许您在Do 方法中使用async/await 并释放线程以执行其他工作。 (更新:这确实应该是 TaskCompletionSource 而不是 Semaphore Slim,但我不会更新此示例,请参阅下面的第二部分)

public async Task<bool> Do(int input)

    using(var completion = new new SemephoreSlim(0,1))
    
        var job = new JobTask(input, completion);
        _workQueue.Add(job);
        await completion.WaitAsync().ConfigureAwait(false);
        return job.ResultData;
    


private void ProcessingLoop()

    foreach(var job in _workQueue.GetConsumingEnumerable())
    
        job.PerformWork(); //Inside PerformWork there is a _completion.Release(); call.
    


要使所有内容自包含,您可以更改 SemaphoreSlim / TaskCompletionSource 并将其放入作业中,然后返回作业本身。

    public JobTask Do(int input)
    
        var job = new JobTask(input);
        _workQueue.Add(job);
        return job;
    

public class JobTask

    private readonly int _input;
    private readonly TaskCompletionSource<bool> _completionSource;

    public JobTask(int input)
    
        _input = input;
        _completionSource = new TaskCompletionSource<bool>();
    

    public void PerformWork()
    
        try
        
            // Do stuff here with _input.

            _completionSource.TrySetResult(true);
        
        catch(Exception ex)
        
            _completionSource.TrySetException(ex);
        
    

    public Task<bool> Work  get  return _completionSource.Task;  

【讨论】:

谢谢@Scott,但我为什么要“做”异步? “Do”函数只是将一个项目(一个特定的“int”)添加到队列中并返回......仅此而已。服务器定期接受一批任务并“执行”。在“添加到队列”之后,我需要等待这个特定的“id”完成。 我认为Do 并不总是返回true 我认为true 来自已完成的工作,因此您需要与您的旧@987654334 一起完成.WaitOne() @ 在Do 方法中的旧代码中。如果返回的 bool 不是来自工作作业,只需让它返回 void。我会以这种方式用一个例子来更新我的答案。 谢谢。我添加了return true,以便 wcf 客户端可以在服务器上完成工作(针对他的 id)时收到响应。 我没有注意到这是 WCF,您可能想考虑为 WCF 使用双工回调方法,这更适合您等待完成的长时间运行的操作。 哦,我读到了双工,确实这是一种更好的方法。如果是双工 wcf 服务,您的答案会有所不同吗?

以上是关于ManualResetEvent 对象数组的主要内容,如果未能解决你的问题,请参考以下文章

将 ManualResetEvent 包装为等待任务

如何使用ThreadPool

将对象数组的对象数组转换为对象的二维数组

js数组对象操作

JavaScript 浅析数组对象与类数组对象

对象数组