using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static int counter = 0;
// I don't know when threads are created / joined, which is why I need this:
static List<WeakReference<ThreadLocalValue>> allStorage =
new List<WeakReference<ThreadLocalValue>>();
// The performance counter
[ThreadStatic]
static ThreadLocalValue local;
class ThreadLocalValue : IDisposable
{
public ThreadLocalValue()
{
// CHANGE HERE!!!
lock (allStorage)
{
allStorage.Add(new WeakReference<ThreadLocalValue>(this));
}
}
public int ctr = 0;
public void Dispose()
{
// CHANGE HERE!!!
Dispose(true);
}
// CHANGE HERE!!!
private void Dispose(bool disposing)
{
// CHANGE HERE!!!
// Reset the counter
int ctr2 = Interlocked.Exchange(ref ctr, 0);
// Atomic add
Interlocked.Add(ref Program.counter, ctr2);
if (disposing)
{
GC.SuppressFinalize(this);
}
}
~ThreadLocalValue()
{
// CHANGE HERE!!!
// Make sure it's merged.
Dispose(false);
}
}
// Create-or-increment
static void LocalInc()
{
if (local == null) { local = new ThreadLocalValue(); }
++local.ctr;
}
static void Main(string[] args)
{
Stopwatch sw = Stopwatch.StartNew();
Parallel.For(0, 100000000, (a) =>
{
LocalInc();
});
foreach (var item in allStorage)
{
ThreadLocalValue target;
if (item.TryGetTarget(out target))
{
target.Dispose();
}
}
// CHANGE HERE!!!
// There could be some finalizer that was already running,
// we wait that they execute their Interlocked.Add
GC.WaitForPendingFinalizers();
Console.WriteLine(sw.Elapsed.ToString());
Console.WriteLine(counter);
Console.ReadLine();
}
}