Executing multithreaded methods make garbage. Why is that and can we prevent it?
ThreadPool.QueueUserWorkItem(callBack, state);
EDIT:
By garbage I mean objects that are created and then went out of scope. The garbage collection is very slow because of it's old version of mono. So every kb you save from the GC is a win. If you are not familiar with the unity engine, In the screenshot please see The GC column on the highlighted row. It says 0.6kb. Therefore it create 600 bytes of garbage. The callback code is not creating any garbage so this is rooted from ThreadPool.QueueUserWorkItem
EDIT 2: To elaborate further here is a more concrete example:
public class TestThread : MonoBehaviour
{
public void Update()
{
if (Time.frameCount%10 == 0)
ThreadPool.QueueUserWorkItem(DummyMethod);
}
public void DummyMethod(object meaningless)
{
}
}
Here is the result. Please look at the highlighted row. The GC column says 285Bytes. Since DummyMethod is not doing anything, the garbage is related to ThreadPool.
Edit 3:
To relax the situation and find an alternative, it would be acceptable to have a worker thread that executes jobs from a queue.
It would be OK But it MUST run on CPU other than the one unity uses if there are multiple CPUs available. Unity does nearly anything in a single thread so a background worker on the same CPU would be a disaster. Also it is a cross platform project so windows-only solutions won't work. So basically I need a worker thread solution and to know if it possible to realize if a thread's CPU is the same as another thread's.
When you ThreadPool.QueueUserWorkItem(DummyMethod); it actually is implicitly turning your code in to ThreadPool.QueueUserWorkItem(new WaitCallback(DummyMethod));, that callback may be the item that is getting put on to the GC. Try the following code to explicitly create the delegate and keep a reference to it and see if it reduces the amount of GCable data.
public class TestThread : MonoBehaviour
{
private readonly WaitCallback _callback;
public TestThread()
{
_callback = new WaitCallback(DummyMethod);
}
public void Update()
{
if (Time.frameCount%10 == 0)
ThreadPool.QueueUserWorkItem(_callback);
}
public void DummyMethod(object meaningless)
{
}
}
UPDATE: Here is a extremely basic implementation of a single threaded background worker, to give you a starting point. The below code is untested and may perform horribly, but it does give you an idea as a starting point.
public class BasicBackgroundWorker
{
private readonly Thread _backgroundWorkThread;
private readonly Queue<Action> _queue = new Queue<Action>();
private readonly ManualResetEvent _workAvailable = new ManualResetEvent(false);
public BasicBackgroundWorker()
{
_backgroundWorkThread = new Thread(BackgroundThread)
{
IsBackground = true,
Priority = ThreadPriority.BelowNormal,
Name = "BasicBackgroundWorker Thread"
};
_backgroundWorkThread.Start();
}
public void EnqueueWork(Action work)
{
lock (_queue)
{
_queue.Enqueue(work);
_workAvailable.Set();
}
}
private void BackgroundThread()
{
while (true)
{
_workAvailable.WaitOne();
Action workItem;
lock (_queue)
{
workItem = _queue.Dequeue();
if (_queue.Count == 0)
{
_workAvailable.Reset();
}
}
try
{
workItem();
}
catch (Exception ex)
{
//Log exception that happened in backgroundWork
}
}
}
}
Related
This question already has answers here:
How to wait for async method to complete?
(7 answers)
Closed 2 years ago.
Let's say I have a MyThread class in my Windows C# app like this:
public class MyThread
{
Thread TheThread;
public MyThread()
{
TheThread = new Thread(MyFunc);
}
public void StartIfNecessary()
{
if (!TheThread.IsAlive)
TheThread.Start();
}
private void MyFunc()
{
for (;;)
{
if (ThereIsStuffToDo)
DoSomeStuff();
}
}
}
That works fine. But now I realize I can make my thread more efficient by using async/await:
public class MyThread
{
Thread TheThread;
public MyThread()
{
TheThread = new Thread(MyFunc);
}
public void StartIfNecessary()
{
if (!TheThread.IsAlive)
TheThread.Start();
}
private async void MyFunc()
{
for (;;)
{
DoSomeStuff();
await MoreStuffIsReady();
}
}
}
What I see now, is that the second time I call StartIfNecessary(), TheThread.IsAlive is false (and ThreadState is Stopped BTW) so it calls TheThread.Start() which then throws the ThreadStateException "Thread is running or terminated; it cannot restart". But I can see that DoMoreStuff() is still getting called, so the function is in fact still executing.
I suspect what is happening, is that when my thread hits the "await", the thread I created is stopped, and when the await on MoreStuffIsReady() completes, a thread from the thread pool is assigned to execute DoSomeStuff(). So it is technically true that the thread I created has been stopped, but the function I created that thread to process is still running.
So how can I tell if "MyFunc" is still active?
I can think of 3 ways to solve this:
1) Add a "bool IsRunning" which is set to true right before calling TheThread.Start(), and MyFunc() sets to false when it completes. This is simple, but requires me to wrap everything in a try/catch/finally which isn't awful but I was hoping there was a way to have the operating system or framework help me out here just in case "MyFunc" dies in some way I wasn't expecting.
2) Find some new function somewhere in System.Threading that will give me the information I need.
3) Rethink the whole thing - since my thread only sticks around for a few milliseconds, is there a way to accomplish this same functionality without creating a thread at all (outside of the thread pool)? Start "MyFunc" as a Task somehow?
Best practices in this case?
Sticking with a Plain Old Thread and using BlockingCollection to avoid a tight loop:
class MyThread
{
private Thread worker = new Thread(MyFunc);
private BlockingCollection<Action> stuff = new BlockingCollection<Action>();
public MyThread()
{
worker.Start();
}
void MyFunc()
{
foreach (var todo in stuff.GetConsumingEnumerable())
{
try
{
todo();
}
catch(Exception ex)
{
// Something went wrong in todo()
}
}
stuff.Dispose(); // should be disposed!
}
public void Shutdown()
{
stuff.CompleteAdding(); // No more adding, but will continue to serve until empty.
}
public void Add( Action stuffTodo )
{
stuff.Add(stuffTodo); // Will throw after Shutdown is called
}
}
BlockingCollection also shows examples with Task if you prefer to go down that road.
Rethink the whole thing
This is definitely the best option. Get rid of the thread completely.
It seems like you have a "consumer" kind of scenario, and you need a consumer with a buffer of data items to work on.
One option is to use ActionBlock<T> from TPL Dataflow:
public class NeedsADifferentName
{
ActionBlock<MyDataType> _block;
public NeedsADifferentName() => _block = new ActionBlock<MyDataType>(MyFunc);
public void QueueData(MyDataType data) => _block.Post(data);
private void MyFunc(MyDataType data)
{
DoSomeStuff(data);
}
}
Alternatively, you can build your own pipeline using something like Channels.
Let's say I have a method that gets called by multiple threads
public class MultiThreadClass
{
public void Gogogo()
{
// method implementation
}
private volatile bool running;
}
in Gogogo(), I want to check if running is true, and if so, return from the method. However, if it is false, I want to set it to true and continue the method. The solution I see is to do the following:
public class MultiThreadClass
{
public void Gogogo()
{
lock (this.locker)
{
if (this.running)
{
return;
}
this.running = true;
}
// rest of method
this.running = false;
}
private volatile bool running;
private readonly object locker = new object();
}
Is there another way to do this? I've found out that if I leave out the lock, running could be false for 2 different threads, set to true, and the rest of the method would execute on both threads simultaneously.
I guess my goal is to have the rest of my method execute on a single thread (I don't care which one) and not get executed by the other threads, even if all of them (2-4 in this case) call Gogogo() simultaneously.
I could also lock on the entire method, but would the method run slower then? It needs to run as fast as possible, but part of it on only one thread at a time.
(Details: I have a dicionary of ConcurrentQueue's which contain "results" which have "job names". I am trying to dequeue one result per key in the dictionary (one result per job name) and call this a "complete result" which is sent by an event to subscribers. The results are sent via an event to the class, and that event is raised from multiple threads (one per job name; each job raises a "result ready" event on it's own thread)
You can use Interlocked.CompareExchange if you change your bool to an int:
private volatile int running = 0;
if(Interlocked.CompareExchange(ref running, 1, 0) == 0)
{
//running changed from false to true
}
I think Interlocked.Exchange should do the trick.
You can use Interlocked to handle this case without a lock, if you really want to:
public class MultiThreadClass
{
public void Gogogo()
{
if (Interlocked.Exchange(ref running, 1) == 0)
{
//Do stuff
running = 0;
}
}
private volatile int running = 0;
}
That said, unless there is a really high contention rate (which I would not expect) then your code should be entirely adequate. Using Interlocked also suffers a bit in the readability department due to not having bool overloads for their methods.
You need to use Monitor class instead of boolean flag. Use Monitor.TryEnter:
public void Gogogo()
{
if Monitor.TryEnter(this.locker)
{
try
{
// Do stuff
}
finally
{
Monitor.Exit(this.locker);
}
}
}
I am working on a web application, where several users can update the same record. So to avoid a problem if users are updating the same record at the same time, I am saving their changes in a queue. When each save occurs, I want to call a method that processes the queue on another thread, but I need to make sure that the method cannot run in another thread if it is called again. I’ve read several posts on the subject, but not sure what is best for my situation. Below is the code I have now. Is this the correct way to handle it?
public static class Queue {
static volatile bool isProcessing;
static volatile object locker = new Object();
public static void Process() {
lock (locker) {
if (!isProcessing) {
isProcessing = true;
//Process Queue...
isProcessing = false;
}
}
}
}
New answer
If you are persisting these records to a database (or data files, or similar persistence system) you should let that underlying system handle the synchronization. As JohnSaunders pointed out Databases already handle simultaneous updates.
Given you want to persist the records… the problem presented by John is that you are only synchronizing the access to the data in a single instance of the web application. Still, there could be multiple instances running at the same time (for example in a server farm, which may be a good idea if you have high traffic). In this scenario using a queue to prevent simultaneous writes is not good enough because there is still a race condition among the multiple instances of the web page.
In that case, when you get updates for the same record from different instances, then the underlying system will have to handle the collision anyway, yet it will not be able to do it reliably because the order of the updates has been lost.
In addition to that problem, if you are using this data structure as a cache, then it will provide incorrect data because it is not aware of the updates that happen in another instance.
With that said, for the scenarios where it may be worth to use a Thread-Safe Queue. For those cases you could use ConcurrentQueue (as I mention at the end of my original answer).
I'll keep my original answer, because I see value in helping understand the threading synchronization mechanism available in .NET (of which I present a few).
Original answer
Using lock is enough to prevent the access of multiple threads to a code segment at the same time (this is mutual exclusion).
Here I have commented out what you don't need:
public static class Queue {
// static volatile bool isProcessing;
static /*volatile*/ object locker = new Object();
public static void Process() {
lock (locker) {
// if (!isProcessing) {
// isProcessing = true;
//Process Queue...
// isProcessing = false;
// }
}
}
}
The lock does NOT need volatile to work. However you might still need the variable to be volatile due to other code not included here.
With that said, all the threads that try to enter in the lock will be waiting in a queue. Which as I understand is not what you want. Instead you want all the other threads to skip the block and leave only one do the work. This can be done with Monitor.TryEnter:
public static class Queue
{
static object locker = new Object();
public static void Process()
{
bool lockWasTaken = false;
try
{
if (Monitor.TryEnter(locker))
{
lockWasTaken = true;
//Process Queue…
}
}
finally
{
if (lockWasTaken)
{
Monitor.Exit(locker);
}
}
}
}
Another good alternative is to use Interlocked:
public static class Queue
{
static int status = 0;
public static void Process()
{
bool lockWasTaken = false;
try
{
lockWasTaken = Interlocked.CompareExchange(ref status, 1, 0) == 0;
if (lockWasTaken)
{
//Process Queue…
}
}
finally
{
if (lockWasTaken)
{
Volatile.Write(ref status, 0);
// For .NET Framework under .NET 4.5 use Thread.VolatileWrite instead.
}
}
}
}
Anyway, you don't have the need to implement your own thread-safe queue. You could use ConcurrentQueue.
A lock is good but it won't work for async await. You will get the following error if you try to await a method call in a lock:
CS1996 Cannot await in the body of a lock statement
In this case you should use a SemaphoreSlim
Example:
public class TestModel : PageModel
{
private readonly ILogger<TestModel> _logger;
private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
public TestModel(ILogger<TestModel> logger)
{
_logger = logger;
}
public async Task OnGet()
{
await _semaphoreSlim.WaitAsync();
try
{
await Stuff();
}
finally
{
_semaphoreSlim.Release();
}
}
}
It is important to not new SemaphoreSlim in the constructor or anywhere else because then it won't work.
https://stackoverflow.com/a/18257065/3850405
https://learn.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=net-5.0
I'm writting an application that does extensive use of multithreading. Some of the threads share an observablecollection using a ReaderWriterLockSlim.
I'm having from time to time a deadlock and I need to know which is the thread holding the lock at the moment of the deadlock. How can I know this? I've looked at the object properties and nothing obvious was there. Currently all I know is which threads are waiting for the lock.
Thanks for your help!
EDIT: Of course I'm talking about finding it at debug time with all the debug information available.
During your deadlock just look at the current threads in the thread debugging panel, go through your call stack and you'll find out which thread took the lock.
If you need to know the thread id in your code, you can always save it staticly, or inherit from readerwriterlockslim and add a thread property.
Here is what I meant.
Just trace the locks and unlocks and when you get to your deadlock the system will halt and the last "Enter" will point you in the direction of the locking thread.
public class ReaderWriterLockSlimExtended : ReaderWriterLockSlim
{
private Thread m_currentOwnerThread = null;
private object m_syncRoot = new object();
public Thread CurrentOwnerThread
{
get
{
lock (m_syncRoot)
{
return m_currentOwnerThread;
}
}
}
public Thread CurrentOwnerThreadUnsafe
{
get
{
return m_currentOwnerThread;
}
}
public new void EnterWriteLock()
{
lock (m_syncRoot)
{
base.EnterWriteLock();
m_currentOwnerThread = Thread.CurrentThread;
}
Debug.WriteLine("Enter Write Lock - Current Thread : {0} ({1})", CurrentOwnerThread.Name, CurrentOwnerThread.ManagedThreadId);
}
public new void ExitWriteLock()
{
Debug.WriteLine("Exit Write Lock - Current Thread : {0} ({1})", CurrentOwnerThread.Name, CurrentOwnerThread.ManagedThreadId);
lock (m_syncRoot)
{
m_currentOwnerThread = null; //Must be null before exit!
base.ExitWriteLock();
}
}
}
You can always try tracing the thread ID just before and after the lock, so you have written record of what happened and who locked it and when. You can write to a file or just check in the debugger output window to see all the traces.
I believe you could use trace breakpoint (Breakpoint -> When Hit...) instead of real tracing code to have quick something in the output window.
ReaderWriterLockSlim is not sealed so you could subclass it and attach whatever information you need that way. The problem is that the useful methods are not virtual so you cannot override them. But, you could add your own methods like EnterReadLockDebug and ExitReadLockDebug and the like which calls EnterReadLock and ExitReadLock behind the scenes in addition to capturing the thread in which the method is called. This is not a great solution because you would have to change all of the call sites. But, if using the debugger is too cumbersome then maybe this would be a reasonable alternative.
There are many variations to theme using conditional compilation. You could detect a Debug vs. Release build and inject the necessary debugging logic depending on which build configuration is active. Inject the debugging information when Debug is active and omit it when Release is active.
This is the code I ended with, for future reference:
using System;
using System.Threading;
namespace Utils
{
public class ReaderWriterLockSlim2
{
#region Attributes
private readonly TimeSpan _maxWait;
private readonly ReaderWriterLockSlim _lock;
#endregion
#region Properties
public int CurrentWriteOwnerId { get; private set; }
public string CurrentWriteOwnerName { get; private set; }
#endregion
#region Public Methods
public ReaderWriterLockSlim2(LockRecursionPolicy policy, TimeSpan maxWait)
{
_maxWait = maxWait;
_lock = new ReaderWriterLockSlim(policy);
}
public void EnterWriteLock()
{
if (!_lock.TryEnterWriteLock(_maxWait))
{
throw new TimeoutException(string.Format("Timeout while waiting to enter a WriteLock. Lock adquired by Id {0} - Name {1}", this.CurrentWriteOwnerId, this.CurrentWriteOwnerName));
}
else
{
this.CurrentWriteOwnerId = Thread.CurrentThread.ManagedThreadId;
this.CurrentWriteOwnerName = Thread.CurrentThread.Name;
}
}
public void ExitWriteLock()
{
_lock.ExitWriteLock();
this.CurrentWriteOwnerId = 0;
this.CurrentWriteOwnerName = null;
}
public void EnterReadLock()
{
_lock.EnterReadLock();
}
public void ExitReadLock()
{
_lock.ExitReadLock();
}
#endregion
}
}
I've found the "ThreadStatic" attribute to be extremely useful recently, but makes me now want a "ThreadLocal" type attribute that lets me have non-static data members on a per-thread basis.
Now I'm aware that this would have some non-trivial implications, but:
Does such a thing exist already built into C#/.net? or since it appears so far that the answer to this is no (for .net < 4.0), is there a commonly used implementation out there?
I can think of a reasonable way to implement it myself, but would just use something that already existed if it were available.
Straw Man example that would implement what I'm looking for if it doesn't already exist:
class Foo
{
[ThreadStatic]
static Dictionary<Object,int> threadLocalValues = new Dictionary<Object,int>();
int defaultValue = 0;
int ThreadLocalMember
{
get
{
int value = defaultValue;
if( ! threadLocalValues.TryGetValue(this, out value) )
{
threadLocalValues[this] = value;
}
return value;
}
set { threadLocalValues[this] = value; }
}
}
Please forgive any C# ignorance. I'm a C++ developer that has only recently been getting into the more interesting features of C# and .net
I'm limited to .net 3.0 and maybe 3.5 (project has/will soon move to 3.5).
Specific use-case is callback lists that are thread specific (using imaginary [ThreadLocal] attribute) a la:
class NonSingletonSharedThing
{
[ThreadLocal] List<Callback> callbacks;
public void ThreadLocalRegisterCallback( Callback somecallback )
{
callbacks.Add(somecallback);
}
public void ThreadLocalDoCallbacks();
{
foreach( var callback in callbacks )
callback.invoke();
}
}
Enter .NET 4.0!
If you're stuck in 3.5 (or earlier), there are some functions you should look at, like AllocateDataSlot which should do what you want.
You should think about this twice. You are essentially creating a memory leak. Every object created by the thread stays referenced and can't be garbage collected. Until the thread ends.
If you looking to store unique data on a per thread basis you could use Thread.SetData. Be sure to read up on the pros and cons http://msdn.microsoft.com/en-us/library/6sby1byh.aspx as this has performance implications.
Consider:
Rather than try to give each member variable in an object a thread-specific value, give each thread its own object instance. -- pass the object to the threadstart as state, or make the threadstart method a member of the object that the thread will "own", and create a new instance for each thread that you spawn.
Edit
(in response to Catskul's remark.
Here's an example of encapsulating the struct
public class TheStructWorkerClass
{
private StructData TheStruct;
public TheStructWorkerClass(StructData yourStruct)
{
this.TheStruct = yourStruct;
}
public void ExecuteAsync()
{
System.Threading.ThreadPool.QueueUserWorkItem(this.TheWorkerMethod);
}
private void TheWorkerMethod(object state)
{
// your processing logic here
// you can access your structure as this.TheStruct;
// only this thread has access to the struct (as long as you don't pass the struct
// to another worker class)
}
}
// now hte code that launches the async process does this:
var worker = new TheStructWorkerClass(yourStruct);
worker.ExecuteAsync();
Now here's option 2 (pass the struct as state)
{
// (from somewhere in your existing code
System.Threading.Threadpool.QueueUserWorkItem(this.TheWorker, myStruct);
}
private void TheWorker(object state)
{
StructData yourStruct = (StructData)state;
// now do stuff with your struct
// works fine as long as you never pass the same instance of your struct to 2 different threads.
}
I ended up implementing and testing a version of what I had originally suggested:
public class ThreadLocal<T>
{
[ThreadStatic] private static Dictionary<object, T> _lookupTable;
private Dictionary<object, T> LookupTable
{
get
{
if ( _lookupTable == null)
_lookupTable = new Dictionary<object, T>();
return _lookupTable;
}
}
private object key = new object(); //lazy hash key creation handles replacement
private T originalValue;
public ThreadLocal( T value )
{
originalValue = value;
}
~ThreadLocal()
{
LookupTable.Remove(key);
}
public void Set( T value)
{
LookupTable[key] = value;
}
public T Get()
{
T returnValue = default(T);
if (!LookupTable.TryGetValue(key, out returnValue))
Set(originalValue);
return returnValue;
}
}
Although I am still not sure about when your use case would make sense (see my comment on the question itself), I would like to contribute a working example that is in my opinion more readable than thread-local storage (whether static or instance). The example is using .NET 3.5:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Linq;
namespace SimulatedThreadLocal
{
public sealed class Notifier
{
public void Register(Func<string> callback)
{
var id = Thread.CurrentThread.ManagedThreadId;
lock (this._callbacks)
{
List<Func<string>> list;
if (!this._callbacks.TryGetValue(id, out list))
{
this._callbacks[id] = list = new List<Func<string>>();
}
list.Add(callback);
}
}
public void Execute()
{
var id = Thread.CurrentThread.ManagedThreadId;
IEnumerable<Func<string>> threadCallbacks;
string status;
lock (this._callbacks)
{
status = string.Format("Notifier has callbacks from {0} threads, total {1} callbacks{2}Executing on thread {3}",
this._callbacks.Count,
this._callbacks.SelectMany(d => d.Value).Count(),
Environment.NewLine,
Thread.CurrentThread.ManagedThreadId);
threadCallbacks = this._callbacks[id]; // we can use the original collection, as only this thread can add to it and we're not going to be adding right now
}
var b = new StringBuilder();
foreach (var callback in threadCallbacks)
{
b.AppendLine(callback());
}
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine(status);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(b.ToString());
}
private readonly Dictionary<int, List<Func<string>>> _callbacks = new Dictionary<int, List<Func<string>>>();
}
public static class Program
{
public static void Main(string[] args)
{
try
{
var notifier = new Notifier();
var syncMainThread = new ManualResetEvent(false);
var syncWorkerThread = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(delegate // will create closure to see notifier and sync* events
{
notifier.Register(() => string.Format("Worker thread callback A (thread ID = {0})", Thread.CurrentThread.ManagedThreadId));
syncMainThread.Set();
syncWorkerThread.WaitOne(); // wait for main thread to execute notifications in its context
syncWorkerThread.Reset();
notifier.Execute();
notifier.Register(() => string.Format("Worker thread callback B (thread ID = {0})", Thread.CurrentThread.ManagedThreadId));
syncMainThread.Set();
syncWorkerThread.WaitOne(); // wait for main thread to execute notifications in its context
syncWorkerThread.Reset();
notifier.Execute();
syncMainThread.Set();
});
notifier.Register(() => string.Format("Main thread callback A (thread ID = {0})", Thread.CurrentThread.ManagedThreadId));
syncMainThread.WaitOne(); // wait for worker thread to add its notification
syncMainThread.Reset();
notifier.Execute();
syncWorkerThread.Set();
syncMainThread.WaitOne(); // wait for worker thread to execute notifications in its context
syncMainThread.Reset();
notifier.Register(() => string.Format("Main thread callback B (thread ID = {0})", Thread.CurrentThread.ManagedThreadId));
notifier.Execute();
syncWorkerThread.Set();
syncMainThread.WaitOne(); // wait for worker thread to execute notifications in its context
syncMainThread.Reset();
}
finally
{
Console.ResetColor();
}
}
}
}
When you compile and run the above program, you should get output like this:
alt text http://img695.imageshack.us/img695/991/threadlocal.png
Based on your use-case I assume this is what you're trying to achieve. The example first adds two callbacks from two different contexts, main and worker threads. Then the example runs notification first from main and then from worker threads. The callbacks that are executed are effectively filtered by current thread ID. Just to show things are working as expected, the example adds two more callbacks (for a total of 4) and again runs the notification from the context of main and worker threads.
Note that Notifier class is a regular instance that can have state, multiple instances, etc (again, as per your question's use-case). No static or thread-static or thread-local is used by the example.
I would appreciate if you could look at the code and let me know if I misunderstood what you're trying to achieve or if a technique like this would meet your needs.
I'm not sure how you're spawning your threads in the first place, but there are ways to give each thread its own thread-local storage, without using hackish workarounds like the code you posted in your question.
public void SpawnSomeThreads(int threads)
{
for (int i = 0; i < threads; i++)
{
Thread t = new Thread(WorkerThread);
WorkerThreadContext context = new WorkerThreadContext
{
// whatever data the thread needs passed into it
};
t.Start(context);
}
}
private class WorkerThreadContext
{
public string Data { get; set; }
public int OtherData { get; set; }
}
private void WorkerThread(object parameter)
{
WorkerThreadContext context = (WorkerThreadContext) parameter;
// do work here
}
This obviously ignores waiting on the threads to finish their work, making sure accesses to any shared state is thread-safe across all the worker threads, but you get the idea.
Whilst the posted solution looks elegant, it leaks objects. The finalizer - LookupTable.Remove(key) - is run only in the context of the GC thread so is likely only creating more garbage in creating another lookup table.
You need to remove object from the lookup table of every thread that has accessed the ThreadLocal. The only elegant way I can think of solving this is via a weak keyed dictionary - a data structure which is strangely lacking from c#.