Skip to content

Instantly share code, notes, and snippets.

@malaybaku
Created April 23, 2019 11:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save malaybaku/f608d851933e6af7e68159d3bf51d785 to your computer and use it in GitHub Desktop.
Save malaybaku/f608d851933e6af7e68159d3bf51d785 to your computer and use it in GitHub Desktop.
Bad lock statement for produce - consume purposed queue
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
namespace QueueTests
{
class Program
{
static void Main()
{
//Thread safe code
TestConcurrent();
//Thread unsafe code: try one of the following
//You will get correct output, or incorrect output, or dead lock. Please try some times.
//TestNotConcurrent();
new NonThreadSafeLockExample().Test();
Console.ReadKey();
}
static void TestConcurrent()
{
var queue = new ConcurrentQueue<long>();
void Produce()
{
for (int i = 0; i < 100000; i++)
{
queue.Enqueue(i);
}
}
void Consume()
{
long sum = 0;
int consumeCount = 0;
while (consumeCount < 100000)
{
if (queue.TryDequeue(out long res))
{
consumeCount++;
sum += res;
}
}
Console.WriteLine($"Sum={sum}");
}
//OK
Produce();
Consume();
//OK
var t1 = new Thread(Produce);
var t2 = new Thread(Consume);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
}
static void TestNotConcurrent()
{
var queue = new Queue<long>();
void Produce()
{
for (int i = 0; i < 100000; i++)
{
queue.Enqueue(i);
}
}
void Consume()
{
long sum = 0;
int consumeCount = 0;
while (consumeCount < 100000)
{
while (queue.Count > 0)
{
consumeCount++;
long res = queue.Dequeue();
sum += res;
}
}
Console.WriteLine($"Sum={sum}");
}
//OK
Produce();
Consume();
//NG
var t1 = new Thread(Produce);
var t2 = new Thread(Consume);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
}
}
class NonThreadSafeLockExample
{
private readonly object _queueLock = new object();
private readonly Queue<long> _queue = new Queue<long>();
private Queue<long> MyQueue
{
//locked during getting the reference = NOT locked when you Enqueue or Dequeue.
get { lock (_queueLock) return _queue; }
}
public void Test()
{
void Produce()
{
for (int i = 0; i < 100000; i++)
{
MyQueue.Enqueue(i);
}
}
void Consume()
{
long sum = 0;
int consumeCount = 0;
while (consumeCount < 100000)
{
while (MyQueue.Count > 0)
{
consumeCount++;
long res = MyQueue.Dequeue();
sum += res;
}
}
Console.WriteLine($"Sum={sum}");
}
//OK
Produce();
Consume();
//NG
var t1 = new Thread(Produce);
var t2 = new Thread(Consume);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment