C#, Thread-safe?
OK, let's write a kind of Dictionary
that supports increasing and summing of values. Oh, and it's thread-safe. It even says so in its name:
public class ThreadSafeCounter<TKey>
{
private Dictionary<TKey, int> _dictionary = new Dictionary<TKey, int>();
private object _lock = new object();
public bool ContainsKey(TKey key)
{
lock (_lock) { return _dictionary.ContainsKey(key); }
}
public void Add(TKey key, int value)
{
lock (_lock) { _dictionary[key] = value; }
}
public void Inc(TKey key)
{
lock (_lock) { _dictionary[key]++; }
}
public int GetSum()
{
lock (_lock) { return _dictionary.Values.Sum(); }
}
}
So, since it's obviously thread-safe, let's fill it using several threads. What could possibly go wrong?
private void FillCounter(ThreadSafeCounter<int> counter)
{
for (int i = 0; i < 10; i++)
{
if (counter.ContainsKey(i))
{
counter.Inc(i);
}
else
{
counter.Add(i, 1);
}
}
}
public void Test()
{
var counter = new ThreadSafeCounter<int>();
var thread = new Thread(() => FillCounter(counter));
thread.Start();
FillCounter(counter);
thread.Join();
int sum = counter.GetSum();
if (sum != 20)
{
Console.WriteLine("What? Test failed!");
}
}
If you know a bit about multi-threading, the problem in the test should be boringly obvious (Is that a word? "boringly"). But it might fool novices.
While each operation of ThreadSafeCounter is indeed thread-safe, the way the counter is used is not. Between checking for the existence of the key and adding it, the other thread might do the same. So, both threads end up setting the counter to 1 and none actually increases it. A classical race condition.
4I'm voting to close this question as off-topic because [tag:underhanded] questions are off-topic. – Post Rock Garf Hunter – 2017-08-02T20:21:18.447