Your scenario like ConcerentQueue without bounding. So you don't need to use CompleteAdding:
// Initialize Q and Cancelleation Token
var q = new BlockingCollection<int>();
var cts = new CancellationTokenSource();
var ct = cts.Token;
// Producer Thread.
var t1 = Task.Run(() =>
{
int i = 0;
do
{
q.Add(++i);
Console.WriteLine(i + " is added to q");
}
while (!ct.IsCancellationRequested);
Console.WriteLine("producer task is canceled");
}, ct);
// Consumer Thread.
var t2 = Task.Run(() =>
{
do
{
while(q.Count > 0)
{
var result = q.Take();
Console.WriteLine(result + " is removed from q");
}
}
while (!ct.IsCancellationRequested);
Console.WriteLine("consumer task is canceled");
}, ct);
To see in action, create a console app and copy the above code in the main function:
using System;
using System.Threading;
using System.Collections.Concurrent;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
// Copy above code here
Console.Title = "Press any key to exit";
Console.ReadLine();
Console.Title = "Wait to Queue get empty";
// Cancel t1 & t2
cts.Cancel();
// Wait for both thread to done
Task.WaitAll(t1, t2);
}
}
}
See this example for using CompleteAdding.