Using Task Parallel Library in .net 4.0, I want to know what is the best solution to this situation :
My code is starting a task that do a lot of long running steps (steps need to be done one after other).
I have an object Result that aggregate the result of each steps.
The result object is modified in the task ( so in the thread related to this task ).
I also have an web service where we can fetch the current Result object to see the progress of the task.
So the Result object is a share object between the task and the main thread of my code. What is the best approach to implement this to be sure I don't have threading issues and things like that ?
Here a sample of what i'm talking about. Just note that _doWork would not be a static like in the code, it will be a member in another class higher in the hierarchy.
using System.Threading.Tasks;
namespace ConsoleApplication
{
public class Step1Result
{
}
public class Step2Result
{
}
public class Result
{
public Step1Result Step1Result;
public Step2Result Step2Result;
}
class DoWork
{
public Result Result;
public DoWork()
{
Result = new Result();
}
public void Process()
{
// Execute Step 1
Result.Step1Result = Step1();
Result.Step2Result = Step2();
// Other Steps ( long - running )
}
public Step1Result Step1()
{
// Long running step that can takes minutes
return new Step1Result();
}
public Step2Result Step2()
{
// Long running step that can takes minutes
return new Step2Result();
}
}
class Program
{
private static DoWork _doWork;
static void Main(string[] args)
{
_doWork = new DoWork();
var task = Task.Factory.StartNew(() => _doWork.Process());
task.Wait();
}
// This method will be called from a web service at anytime.
static Result CalledFromWebService()
{
return _doWork.Result;
}
}
}
The trouble here is accessing _doWork.Result from both the Task and the Main thread. True ? What could be done to overcome this ?
I would change DoWork.Result property to GetCurrentResult() method and return each time a new copy of current operation result (you can copy object using MemberwiseClone). I dont see any need to share the same object.
Additionalty, I would use ReadWriteLockSlim. So DoWork class will look like this
class DoWork
{
private readonly Result _result;
private readonly ReadWriteLockSlim _lock = new ReadWriteLockSlim();
public DoWork()
{
_result = new Result();
}
public void Process()
{
// Execute Step 1
Step1Result st1result = Step1();
try
{
_lock.EnterWriteLock();
_result.Step1Result = st1result;
}
finally
{
_lock.ExitWriteLock();
}
Step2Result st2result = Step2();
try
{
_lock.EnterWriteLock();
_result.Step2Result = st2result;
}
finally
{
_lock.ExitWriteLock();
}
// Other Steps ( long - running )
}
public Step1Result Step1()
{
// Long running step that can takes minutes
return new Step1Result();
}
public Step2Result Step2()
{
// Long running step that can takes minutes
return new Step2Result();
}
public Result GetCurrentResult()
{
try
{
_lock.EnterReadLock();
return (Result)_result.MemberwiseCopy();
}
finally
{
_lock.ExitReadLock();
}
}
}
If I understand the problem correctly you don't have thread safety issues accessing the Result object.
As you say the steps have to be finished one after each other so you won't be able to run them concurrently.
So inside Process() you can start Step1 in a task, then .Continue with Step2 in another task etc
Therefore you have a single writer thread and no concurrency issues. In this scenario it doesn't matter if you have another thread accessing the
result if that's a read-only fetching thread
You would only need a concurrent collection like ConcurrentDictionary to store the result if you were accessing a collection from different threads.
You would only need a ReadWriteLockSlim if the steps are not run one after each other and you had more than one writer
Your only concern here is dirty reads of the Result object returned from CalledFromWebService. You could add boolean properties to your Result object and remove the need for locks like so:
public class Result
{
public volatile bool IsStep1Valid;
public Step1Result Step1Result;
public volatile bool IsStep2Valid;
public Step2Result Step2Result;
}
Assignment to boolean values are atomic, so you don't have to worry about dirty reads and writes. You could then use those boolean values in your Process method like so:
public void Process()
{
// Execute Step 1
Result.Step1Result = Step1();
Result.IsStep1Valid = true;
Result.Step2Result = Step2();
Result.IsStep2Valid = true;
// Other Steps ( long - running )
}
Notice that the assignment to IsStep1Valid is after the assignment to Step1Result this ensures that Step1Result has a value assigned to it from the Task before IsStep1Valid is set to true.
Now when you access the result in your main thread by calling CalledFromWebService you can simply do the following:
void MyCode() {
var result = Program.CalledFromWebService();
if (result.IsStep1Valid) {
// do stuff with result.Step1Result
} else {
// if need be notify the user that step 1 is not complete yet
}
if (result.IsStep2Valid) {
// do stuff with result.Step2Result
}
// etc.
}
Checking the value of IsStep1Valid before you try to access the Step1Result property ensures that you are not getting a dirty read of the Step1Result property.
Update: A separate web service will not have access to the result object in the windows service because they run in separate app domains. You will need to expose a web service from inside your windows service, and have the main thread of the windows service load the web service and call your background task. You don't have to publicly expose this web service. You can still host a web service in IIS or where ever you originally intended. It would simply call the web service hosted by the windows service.
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.
I am trying to write a unit test that can hit a piece of threaded code 100% of the time for code coverage. The code can ONLY be reached in the context of a threaded application, and is engineered to be hit only once for every object instance in order to minimize lock time expense.
As a simplified example:
public class Example
{
private readonly object lockObject = new object();
private int? objectToInit = null;
public void EnsureObjectInit()
{
//To minimize hitting the lock code, the object is checked first.
if (!objectToInit.HasValue)
{
lock (lockObject)
{
//Then it is checked once more to ensure that it wasn't initiazlized
//before the lock was hit.
if (objectToInit.HasValue)
{
//This block can only be executed if a second thread is able to
//get to the lock before the first can initialize the object.
return;
}
objectToInit = 0;
}
}
}
}
To get code coverage to hit the code inside the second if statement, I've tried code like this:
[TestClass]
public class ExampleTest
{
[Test Method]
public void async MyTest()
{
Example example = new Example();
void runTask()
{
example.EnsureObjectInit();
}
//I've tried increasing the number of threads, but it doesn't make
//it hit the noted code any more consistently.
List<Task> tasks = new List<Task>(2);
tasks.Add(Task.Run(runTask));
tasks.Add(Task.Run(runTask));
await Task.WhenAll(tasks);
... perform extra validation ...
}
}
But code coverage fails to reach the inner if block at least 50% of the time.
Is there any way to force the unit tested code to stop the first thread before initializing the object so that the second thread can get into the first "if" block?
It's a bit of a hack, but you could use reflection to get the lockObject from the Example class instance. Then lock it manually in the ExampleTest method. NOTE: this is a highly couple test. If you change the name of the lock the test will fail.
private class LockExample
{
private readonly object lockObject = new object();
public void TestLock()
{
lock(lockObject)
{
//Do something
}
}
}
private class LockTest
{
public void Test()
{
var example = new LockExample();
var lockOjbect = typeof(LockExample).GetField("lockObject", BindingFlags.NonPublic|BindingFlags.Instance).GetValue(example);
lock (lockOjbect)
{
var task = Task.Run((Action)example.TestLock);
task.Wait(1); //allow the other thread to run
}
}
}
With a slight design change you can make your code easier testable: Extract the access to objectToInit.HasValue into a helper method like hasObjectToInitValue(). In your test, you can then override that method and can then test the scenario that the helper method on first call returns false and on second returns true.
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 have simple method in my C# app, it picks file from FTP server and parses it and stores the data in DB. I want it to be asynchronous, so that user perform other operations on App, once parsing is done he has to get message stating "Parsing is done".
I know it can achieved through asynchronous method call but I dont know how to do that can anybody help me please??
You need to use delegates and the BeginInvoke method that they contain to run another method asynchronously. A the end of the method being run by the delegate, you can notify the user. For example:
class MyClass
{
private delegate void SomeFunctionDelegate(int param1, bool param2);
private SomeFunctionDelegate sfd;
public MyClass()
{
sfd = new SomeFunctionDelegate(this.SomeFunction);
}
private void SomeFunction(int param1, bool param2)
{
// Do stuff
// Notify user
}
public void GetData()
{
// Do stuff
sfd.BeginInvoke(34, true, null, null);
}
}
Read up at http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx
try this method
public static void RunAsynchronously(Action method, Action callback) {
ThreadPool.QueueUserWorkItem(_ =>
{
try {
method();
}
catch (ThreadAbortException) { /* dont report on this */ }
catch (Exception ex) {
}
// note: this will not be called if the thread is aborted
if (callback!= null) callback();
});
}
Usage:
RunAsynchronously( () => { picks file from FTP server and parses it},
() => { Console.WriteLine("Parsing is done"); } );
Any time you're doing something asynchronous, you're using a separate thread, either a new thread, or one taken from the thread pool. This means that anything you do asynchronously has to be very careful about interactions with other threads.
One way to do that is to place the code for the async thread (call it thread "A") along with all of its data into another class (call it class "A"). Make sure that thread "A" only accesses data in class "A". If thread "A" only touches class "A", and no other thread touches class "A"'s data, then there's one less problem:
public class MainClass
{
private sealed class AsyncClass
{
private int _counter;
private readonly int _maxCount;
public AsyncClass(int maxCount) { _maxCount = maxCount; }
public void Run()
{
while (_counter++ < _maxCount) { Thread.Sleep(1); }
CompletionTime = DateTime.Now;
}
public DateTime CompletionTime { get; private set; }
}
private AsyncClass _asyncInstance;
public void StartAsync()
{
var asyncDoneTime = DateTime.MinValue;
_asyncInstance = new AsyncClass(10);
Action asyncAction = _asyncInstance.Run;
asyncAction.BeginInvoke(
ar =>
{
asyncAction.EndInvoke(ar);
asyncDoneTime = _asyncInstance.CompletionTime;
}, null);
Console.WriteLine("Async task ended at {0}", asyncDoneTime);
}
}
Notice that the only part of AsyncClass that's touched from the outside is its public interface, and the only part of that which is data is CompletionTime. Note that this is only touched after the asynchronous task is complete. This means that nothing else can interfere with the tasks inner workings, and it can't interfere with anything else.
Here are two links about threading in C#
Threading in C#
Multi-threading in .NET: Introduction and suggestions
I'd start to read about the BackgroundWorker class
In Asp.Net I use a lot of static methods for jobs to be done. If its simply a job where I need no response or status, I do something simple like below. As you can see I can choose to call either ResizeImages or ResizeImagesAsync depending if I want to wait for it to finish or not
Code explanation: I use http://imageresizing.net/ to resize/crop images and the method SaveBlobPng is to store the images to Azure (cloud) but since that is irrelevant for this demo I didn't include that code. Its a good example of time consuming tasks though
private delegate void ResizeImagesDelegate(string tempuri, Dictionary<string, string> versions);
private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions)
{
ResizeImagesDelegate worker = new ResizeImagesDelegate(ResizeImages);
worker.BeginInvoke(tempuri, versions, deletetemp, null, null);
}
private static void ResizeImages(string tempuri, Dictionary<string, string> versions)
{
//the job, whatever it might be
foreach (var item in versions)
{
var image = ImageBuilder.Current.Build(tempuri, new ResizeSettings(item.Value));
SaveBlobPng(image, item.Key);
image.Dispose();
}
}
Or going for threading so you dont have to bother with Delegates
private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions)
{
Thread t = new Thread (() => ResizeImages(tempuri, versions, null, null));
t.Start();
}
ThreadPool.QueueUserWorkItem is the quickest way to get a process running on a different thread.
Be aware that UI objects have "thread affinity" and cannot be accessed from any thread other than the one that created them.
So, in addition to checking out the ThreadPool (or using the asynchronous programming model via delegates), you need to check out Dispatchers (wpf) or InvokeRequired (winforms).
In the end you will have to use some sort of threading. The way it basically works is that you start a function with a new thread and it will run until the end of the function.
If you are using Windows Forms then a nice wrapper that they have for this is call the Background Worker. It allows you to work in the background with out locking up the UI form and even provides a way to communicate with the forms and provide progress update events.
Background Worker
.NET got new keyword async for asonchrynous functions. You can start digging at learn.microsoft.com (async). The shortest general howto make function asonchrynous is to change function F:
Object F(Object args)
{
...
return RESULT;
}
to something like this:
async Task<Object> FAsync(Object args)
{
...
await RESULT_FROM_PROMISE;
...
return RESULT;
}
The most important thing in above code is that when your code approach await keyword it return control to function that called FAsync and make other computation until promissed value has been returned and procede with rest of code in function FAsync.
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#.