Created
April 23, 2019 11:51
-
-
Save malaybaku/f608d851933e6af7e68159d3bf51d785 to your computer and use it in GitHub Desktop.
Bad lock statement for produce - consume purposed queue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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