2

I don't understand the explanation in offical document:

Logical threads can jump from one managed thread to another.

What's the different between ThreadContext and ThreadLogicalContext? Can someone elaborate on it?

Thanks.

Ricky
  • 34,377
  • 39
  • 91
  • 131
  • see also this question http://stackoverflow.com/questions/3841075/what-is-the-difference-between-log4net-threadcontext-and-log4net-logicalthreadcon – Stefan Egli Dec 22 '10 at 10:58

2 Answers2

5

I should go back and add this to my own question (that Stefan Egli linked above) ...

From what I can tell, there is very little practical difference between the two.

ThreadContext stores information in a Dictionary that is stored using Thread.SetData.

ThreadLogicalContext stores its information in a Dictionary that is stored using the CallContext.

Information stored in the CallContext has almost the same accessibility as information stored using Thread.SetData. That is, the information is accessibli to the thread that stored the information in the first place.

Now, IF the ThreadLogicalContext used CallContext.LogicalSetData (or if the Dictionary stored using CallContext.SetData implemented the marker interface, IThreadAffinative) then there WOULD be BIG difference. In that case, any information stored (LogicalSetData) could be accessed within the same thread AND is passed to child threads. In addition (flows with the logical thread), the information can flow across remoting calls and across AppDomains (if the data is Serializable).

I would have put in some links, but am working from iPhone so is a little awkward. There are some good links in the link that Stefan Egli posted above.

Also, look at Jeffrey Richter's blog from September for an article on CallContext.LogicalSetData. I used his test program as a basis for comparing CallContext.SetData vs CallContext.LogicalSetData vs Thread.SetData vs [ThreadStatic]. Last time I checked, it was the last thing he posted.

Will try to come back and post more links and/or some sample code when I have easy access to computer.

Good luck!

wageoghe
  • 27,390
  • 13
  • 88
  • 116
3

From using this myself, I see the benefit of using the ThreadLogicalContext when working with multi threaded logic (async, await).

For example, if you set the property on your original calling thread using ThreadContext, it is also available to any other tasks that get to run on the same thread.

// caller thread (thread #1)
log4net.ThreadContext.Properties["MyProp"] = "123"; // now set on thread #1
log("start");
await Task.WhenAll(
  MyAsync(1), // `Issue` if task run on thread #1, it will have "MyProp"
  MyAsync(2)  // `Issue` if task run on thread #1, it will have "MyProp"
);
log("end"); // `Issue` only by random chance will you run on thread #1 again

Where as if you use ThreadLogicalContext, it stays on the calling context.

// caller thread (thread #1)
log4net.LogicalThreadContext.Properties["MyProp"] = "123"; // now set on calling context
log("start");
await Task.WhenAll(
    MyAsync(1), // if task run on thread #1, there is no "MyProp"
    MyAsync(2)  // if task run on thread #1, there is no "MyProp"
);
log("end"); // if task run on thread #1, there is no "MyProp"

With await you are never guaranteed you come back to the same thread as when you started and the calling context will have changed, so you will have to set the property again.

...
log4net.LogicalThreadContext.Properties["MyProp"] = "123";
log("end");
Tommy G.
  • 355
  • 2
  • 9
  • It doesn't even have to be multithreaded. For .NET web apps for instance the framework does thread switching when necessary which would basically render ThreadContext useless as it will only work if the entire request runs on the same thread which is possible but isn't guaranteed. So when requests switches threads you lose any context bound to the thread it was running on. – Sergey Akopov Nov 18 '16 at 18:49
  • Yes it works well with async/await code ... stick stuff into LogicalThreadContext so these values are available to be logged out using log4net when your many async calls further in (otherwise you would have to pass them in to the calls as a parameter instead which is messy) – andrew pate May 09 '19 at 16:51