Не достичь кода, как ожидалось
У меня есть приложение для телефонии, в котором я хочу вызывать одновременные вызовы. Каждый звонок будет занимать канал или порт. Поэтому я добавил все каналы в коллекцию 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");
Однако этого не было. Пожалуйста, смотрите снимок.
Приложение просто висит после выхода последнего канала. Я думаю, что я могу использовать блокирующий набор неправильно. Спасибо за помощь.
ОБНОВИТЬ:
Даже я изменил код с помощью 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 ответ
Я считаю, что проблема в том, что ты никогда не звонишь bc.CompleteAdding()
: if
означает, что это будет вызвано в ports + 1
-я итерация цикла, но цикл повторяется только ports
шрифт Times. Из-за этого, GetConsumingEnumerable()
возвращает последовательность, которая никогда не заканчивается, что означает foreach
внутри SimultaneousCall()
блоки навсегда.
Я думаю, что правильным решением будет позвонить bc.CompleteAdding()
после for
цикл, а не в невозможном состоянии внутри него.