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