ManualResetEvent对象的数组

时间:2016-09-30 16:45:17

标签: c# .net multithreading wcf synchronization

这是我的故事:我有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对象。我将确实有一个同步对象数组。这是我的问题的好方法吗?

或者在我的情况下是否有更好的同步类?喜欢等待和脉冲?

感谢您的帮助,

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

1 个答案:

答案 0 :(得分:2)

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

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