У меня есть простая установка производителя-потребителя, использующая блокирующую коллекцию. Потребитель сидит в цикле в течение всего времени работы нашего приложения, ожидая, пока потребитель поместит элементы в коллекцию, затем извлекает элемент и записывает его в последовательный порт. По какой-то причине collection.Take() навсегда блокируется, когда в коллекции есть элементы. Для этого приложения у нас может быть активен один или несколько из этих ProducerConsumers одновременно. Они ведут себя одинаково независимо.
public class ProducerConsumer
{
private Task _backgroundWorker;
private CancellationTokenSource _cancellationTokenSource;
private BlockingCollection<Data> _dataQueue;
public ProducerConsumer()
{
_dataQueue = new BlockingCollection<Data>();
_cancellationTokenSource = new CancellationTokenSource();
_backgroundWorker = new Task(() => DoWork(_cancellationTokenSource.Token), TaskCreationOptions.LongRunning);
_backgroundWorker.Start();
}
public void AddData(Data data)
{
_dataQueue.Add(data);
System.Diagnostics.Debug.WriteLine(_dataQueue.Count);
}
private void DoWork(CancellationToken cancellationToken)
{
while(!cancellationToken.IsCancellationRequested)
{
try
{
_dataQueue.Take(cancellationToken); //This is blocking forever
//DoWork
}
catch(OperationCanceledException) { }
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine(e.ToString());
throw;
}
}
}
}
При выполнении этого оператора печати увеличивается, поэтому у нас определенно есть данные в коллекции, но по какой-то причине Take() продолжает блокироваться.
Он также не генерирует исключение.
Отмена запрашивается с помощью Dispose(), но я этого не добавлял. Это не называется быть вызванным рано.
Я пытался использовать .GetConsumingEnumerable(), и это также блокирует навсегда.
Я неправильно запускаю задачу? Может у меня закончились темы?
Я рассматривал возможность использования BackgroundWorker вместо Task, но согласно MSFT Предпочтение отдается задаче.
Заранее спасибо.
Task.Run
. Если вам нужна длительная задача, используйте TaskFactory.StartNew. Нет нет причин использовать холодные задачи, как это делаете вы. Есть много других странных вещей, например,DoWork
возвращаетTask
, хотя это синхронный метод. Наконец, вы ничего не показываете, вызываяAddData()
- person Panagiotis Kanavos   schedule 02.11.2018new
, для запуска которой требуетсяStart()
. Это никогда не используется - person Panagiotis Kanavos   schedule 02.11.2018Take
иGetConsumingEnumerable
будут ждать, пока либо не будет добавлен новый элемент, либо вы не уведомите коллекцию о завершении добавления чего-либо, вызвавCompleteAdding
. - person ckuri   schedule 02.11.2018