Didn't get to code as expected

I have a telephony application where I want to make concurrent calls. Each call will occupy a channel or port. So I added all channels to the BlockingCollection . The application is a Windows service.

Check out the code.

    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. 

      

The main application has the code:

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

      

Now for the concurrent call code:

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

      

Question: When I tested the application with 4 ports, I thought that the code should reach
Console.WriteLine("Blocking end");

      

However, it is not. See Snapshot. image

The app just hangs after releasing the last channel. I am guessing that I may be using blockingcollection incorrectly. Thanks for the help.

UPDATE:

Even I changed the code with an action POST

like below, the situation hasn't changed.

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


source to share


1 answer


I believe the problem is that you never call bc.CompleteAdding()

: if

means it will be called on the ports + 1

th iteration of the loop, but the loop only ports

iterates over the -times. Because of this, it GetConsumingEnumerable()

returns a sequence that never ends, which means forever foreach

inside the SimultaneousCall()

blocks.



I think the correct solution is to call bc.CompleteAdding()

after the loop for

, not in an impossible state inside it.

+2


source







All Articles