【发布时间】:2014-09-29 21:54:14
【问题描述】:
我有一个电话应用程序,我想在其中调用同时呼叫。每个呼叫将占用一个通道或端口。所以我将所有频道添加到BlockingCollection。该应用程序是一个 Windows 服务。
让我们看看代码。
public static BlockingCollection<Tuple<ChannelResource, string>> bc = new BlockingCollection<Tuple<ChannelResource, string>>();
public static List<string> list = new List<string>();// then add 100 test items to it.
主应用有代码:
while (true)
{
ThreadEvent.WaitOne(waitingTime, false);
lock (SyncVar)
{
Console.WriteLine("Block begin");
for (int i = 0; i < ports; i++)
{
var firstItem = list.FirstOrDefault();
if (bc.Count >= ports)
bc.CompleteAdding();
else
{
ChannelResource cr = OvrTelephonyServer.GetChannel();
bc.TryAdd(Tuple.Create(cr, firstItem));
list.Remove(firstItem);
}
}
pc.SimultaneousCall();
Console.WriteLine("Blocking end");
if (ThreadState != State.Running) break;
}
现在是同时调用代码:
public void SimultaneousCall()
{
Console.WriteLine("There are {0} channels to be processed.", bc.Count);
var workItemBlock = new ActionBlock<Tuple<ChannelResource, string>>(
workItem =>
{
ProcessEachChannel(workItem);
});
foreach (var workItem in bc.GetConsumingEnumerable())
{
bool result = workItemBlock.SendAsync(workItem).Result;
}
workItemBlock.Complete();
}
private void ProcessEachChannel(Tuple<ChannelResource, string> workItem)
{
ChannelResource cr = workItem.Item1;
string sipuri = workItem.Item2;
VoiceResource vr = workItem.Item1.VoiceResource;
workItem.Item1.Disconnected += new Disconnected(workItemItem1_Disconnected);
bool success = false;
try
{
Console.WriteLine("Working on {0}", sipuri);
DialResult dr = new DialResult();
// blah blah for calling....
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", ex.Message);
}
finally
{
if (cr != null && cr.VoiceResource != null)
{
cr.Disconnect();
cr.Dispose();
cr = null;
Console.WriteLine("Release channel for item {0}.", sipuri);
}
}
}
问题是当我用 4 个端口测试应用程序时,我认为代码应该到达
Console.WriteLine("Blocking end");
然而事实并非如此。请看快照。
应用程序在释放最后一个频道后刚刚挂起。我想我可能会错误地使用blockingcollection。感谢您的帮助。
更新:
即使我使用下面的POST 操作更改了代码,情况仍然没有改变。
private bool ProcessEachChannel(Tuple<ChannelResource, string> workItem)
{
// blah blah to return true or false respectively.
public void SimultaneousCall()
{
Console.WriteLine("There are {0} channels to be processed.", bc.Count);
var workItemBlock = new ActionBlock<Tuple<ChannelResource, string>>(
workItem =>
{
bool success = ProcessEachChannel(workItem);
});
foreach (var workItem in bc.GetConsumingEnumerable())
{
workItemBlock.Post(workItem);
}
workItemBlock.Complete();
}
【问题讨论】:
-
@ScottChamberlain,我想返回调用结果来总结一下。说有多少失败或成功,所以我用
ActionBlock.SendAsync(...).Result。 -
我错了,你错误地使用了 bc,而不是在我可以输入答案的计算机上
-
@ScottChamberlain,不着急。我可以等。
-
如果
ProcessEachChannel是同步的,为什么不直接使用Parallel.ForEach而不是使用所有的TPL?找出你的问题仍然很好,但对于这个实现来说这似乎更简单。 -
@MatthewHaugen,我在stackoverflow.com/questions/22688679/… 有旧线程。一条评论指出“如果消费者继续工作并将东西添加到队列中,这将不起作用”由 oleksii。
标签: c# task-parallel-library async-await .net-4.5