C# 等待添加到BlockingCollection

C# 等待添加到BlockingCollection,c#,multithreading,C#,Multithreading,我使用BlockingCollection创建一个队列,多个线程可以在其中添加项目,这些项目由单独的线程处理。添加的项还包含一个回调函数(委托),该函数在处理该项后调用。要添加项目,我使用TryAdd方法 这一切工作正常,但我想知道在运行TryAdd之后是否有任何方法等待处理。 我想要的是,添加线程等待处理完成,然后继续 我希望我能很好地描述我的问题,以便任何人都能给我一个提示 我的目标框架是Mono/.Net4.5。唯一的解决方案是合作——处理方必须向您发出项目已处理的信号。实现这一点非常简单

我使用
BlockingCollection
创建一个队列,多个线程可以在其中添加项目,这些项目由单独的线程处理。添加的项还包含一个回调函数(委托),该函数在处理该项后调用。要添加项目,我使用
TryAdd
方法

这一切工作正常,但我想知道在运行
TryAdd
之后是否有任何方法等待处理。 我想要的是,添加线程等待处理完成,然后继续

我希望我能很好地描述我的问题,以便任何人都能给我一个提示


我的目标框架是Mono/.Net4.5。

唯一的解决方案是合作——处理方必须向您发出项目已处理的信号。实现这一点非常简单-一种方法是:

public struct SignalizableItem<T>
{
  private readonly T _value;
  private readonly TaskCompletionSource<object> _signaller;

  public SignalizableItem(T value, TaskCompletionSource<object> signaller)
  {
    _value = value;
    _signaller = signaller;
  }

  public void Process(Action<T> action)
  {
    try
    {
      action(_value);
      _signaller.SetResult(default(object));
    }
    catch (Exception ex)
    {
      _signaller.SetException(ex);
    }
  }
}

public static class BlockingCollectionExtensions
{
  public static Task QueueAndWaitAsync<T>
     (this BlockingCollection<SignalizableItem<T>> @this, T value)
  {
    var tcs = new TaskCompletionSource<object>();
    @this.Add(new SignalizableItem<T>(value, tcs));
    return tcs.Task;
  }
}
在用户端,您将在准备就绪时打开值和信号:

var item = collection.Take();

item.Process
 (
   data =>
   {
     // Your processing
     ...
   }
 );
当然,集合将是
BlockingCollection
而不是
BlockingCollection

您可以通过添加另一个扩展方法进一步简化处理:

public static void Process<T>
  (this BlockingCollection<SignalizableItem<T>> @this, Action<T> action)
{
  @this.Take().Process(action);
}

抽象掉整个处理机制,只暴露简单的动作委托。

只是出于好奇:你为什么要等待?如果需要同步处理项目,为什么要使用
阻止集合
?您可以只在调用站点处理该项,而不将其添加到集合中。也许我这里遗漏了什么。我怀疑这是重复的。@AlexeiLevenkov:这是如何基于回调的
TryAdd
的?@olydis我想OP提到集合只是为了描述代码。我认为整个问题可以浓缩为“项目包含一个回调函数,该函数在项目被处理后被调用……等待……等待处理完成”。可能是完全错误的-如果OP提供了代码,就可以清楚地知道它是否是case(我将以dup而不是注释的形式关闭)。没错,我的队列项是一个包含要处理的数据和回调函数的结构。如果能够同时进行同步和异步处理,那就太好了。由于数据是发送到外部设备的命令,有时我需要等待响应才能继续,有时响应无关紧要,只会添加到日志文件中。我在哪个名称空间中找到
单元
类型?@Sebastian哦,我的错-我不想传递类型时通常使用
单元
,但我试图把它从样本中去掉;只需将其替换为
对象
public static void Process<T>
  (this BlockingCollection<SignalizableItem<T>> @this, Action<T> action)
{
  @this.Take().Process(action);
}
public static void ProcessAll<T>
  (this BlockingCollection<SignalizableItem<T>> @this, Action<T> action, 
   CancellationToken cancellationToken)
{
  SignalizableItem<T> val;
  while (@this.TryTake(out val, -1, cancellationToken)) val.Process(action);
}