未达到预期的代码

时间:2014-08-06 20:08:08

标签: c# task-parallel-library async-await .net-4.5

我有一个电话应用程序,我想在其中调用同时调用。每次通话都会占用一个通道或端口。所以我将所有频道添加到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");

但事实并非如此。请看快照。 image

应用程序只是在释放最后一个频道后挂起。我猜我可能错误地使用了阻塞集合。谢谢你的帮助。

更新

即使我使用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();
    }

1 个答案:

答案 0 :(得分:2)

我认为问题在于你永远不会调用bc.CompleteAdding()if意味着它将在ports + 1中被调用 - 循环的迭代,但循环仅迭代{{1 }} - 倍。因此,ports会返回一个永不结束的序列,这意味着GetConsumingEnumerable()内的foreach会永久阻止。

我认为正确的解决方案是在 SimultaneousCall()循环之后调用bc.CompleteAdding() ,而不是在其中的不可能条件下。