2

I had an idea for solving the problem of enumerating managed threads in .Net and for tracking thread ancestry (which thread created which other thread).

If it were possible to tag a Thread object with an object of the programmer's making that is automatically copied to children threads when they are created, it might be possible to use that tag to track when new threads are created, who created them, etc. The inspiration came from unix, where, when a process is forked, it inherits open file handles, etc. If there were some piece of data that is 1) thread-local or tied to a Thread object and 2) is automatically copied to new threads and 3) is modifiable, that would be a good start.

I'm guessing that we'll have to use reflection to access members of some of the Thread object that starts the chain because most of what i see in the thread that might be useful is otherwise locked up, but it's an start. I'm not sure how wise this approach is though.

Edit: I think I'll explain my use case better because I don't think anybody understands.

I know about tracking threads explicitly, which I've done widely in code i own before. That's not the problem.

Basically, I'm trying to implement a 'thread-group-context', much in the same way that .Net has an appdomain-context, a remoting context [1] and an assembly-thread combination-local context [2].

For a given group of threads that were spawned from a common thread, I want to associate information with that grouping. While I understand that .Net doesn't have this concept (else I would have no problem!), it doesn't change the fact that every managed thread in .Net was created by one and only one other managed thread, and thus, can be drawn in a tree structure.

The problem I am trying to solve is thus: I have an API, that has an context object. This API calls into a large external library of code that does real work, and does so starting from a thread of its creation. That external does not explicitly get a copy of the API context object, however it would need one in order to make calls on the API. Since it does not have a reference to the API context object, it cannot make these calls. As things stand today, the external library does need to make calls, and to do so it looks up the current context object in a single static field, meaning that there can only be one instance of my API per AppDomain. I wish to fix this.

This external library is partly out of my control, and the interface between my API and the external library does not explicitly pass the context object. Up until now, when the external library needed to make calls into the API, it would look at a static field in my API to get a reference to the context object.

The problem is then that a final executable can only have one instance of my API session per AppDomain, because we're using static fields to pass the context object to the external library (workhorse) code.

One option is to make a GetContextObject() method in my API. When the API spawns the thread to run the external library code, it would remember that thread in a shared static dictionary. When the external library code calls GetContextObject(), it would look up what thread it is running on and return the proper context object for that thread.

If the external library code never created its own threads, then I'd have no problem, I'd always have a 100% correct mapping of thread to context. However, the external library does make its own threads, and does so without my API being aware. When the API receives a call from those threads, it won't know what context object to give up, and has to guess - if there's only one context object registered, it uses that, otherwise, it throws an exception saying it can't tell you.

If I could have data tagged to thread objects that is inherited by threads created by that parent thread, then I could implement this tracking system.

Also, the external library does not use the thread pool.

Basically, my options are thus:

1) Redesign the interface between my API and the external library to pass in the context object, and redesign the external library to correctly pass around this context object. Involves trundling through ~1 million LOC.

1a) Forbid the external library from directly using the Thread object, and instead require them to use my own MyApiThread object that, when created, adds itself to my custom tracking mechanism. Requires changing less code in the external library than option #1, but still involves a lot of rework.

2) Force the consumer of my API to start each API session in a new AppDomain so that I can store my context object in a static field (this is the 'solution' today). AppDomains involve a lot of overhead and I do not wish to force this upon my users.

3) Find a way to track thread ancestry to be able to return the correct context object to the code calling from the external library based on the calling thread. This is the subject of this post.

To those saying that Windows does not have a concept of child-parent threading, you are off base - that is irrelevant. DotNet is not a Windows-only system, and its very design was to isolate it from the machine and OS it is running on, which is why .Net exists for Linux, Solaris, FreeBSD in the form of Mono. Furthermore, Java does have the very concept of thread ancestry that I need, and Java is implemented on Windows, thus this is a very possible and reasonable concept. While I realize that the .Net api has a certain Microsoft-specific bend to it, realize that, largely, .Net and Windows are independent.

antiduh
  • 11,853
  • 4
  • 43
  • 66
  • Please don't prefix your titles with "C# / .Net - " and such. That's what the tags are for. – John Saunders Jan 19 '12 at 23:38
  • Also, what do you mean by "child threads"? .NET doesn't really have that concept? Do you just mean "threads created by thread A are children of thread A?" – John Saunders Jan 19 '12 at 23:39
  • Ah, thanks for the editing tip. I do mean "thread A created by thread B" - .Net doesn't provide any way to track this, which is the crux of my problem. – antiduh Jan 20 '12 at 00:05
  • 1
    I don't think it's a good idea to keep track of "child tasks". Instead, have a data structure in your code that tracks the structure of the work that needs to be done. One of the members of that structure can be the thread id of the thread doing the work. Or use Tasks in .NET 4.0 and store the Task in that structure. This way, you're not dependent on accidents of who creates which thread. – John Saunders Jan 20 '12 at 00:11
  • Thanks for the tip, but it's not helpful. In an application in which I have complete control, yes, I would much rather simply keep track of threads explicitly. Unfortunately, the system I'm working with is large and has some unfortunate designs that I'm trying to fix / workaround in ways better than what exist today. – antiduh Jan 20 '12 at 13:57
  • 1
    There probably is a better, more explicit way of doing what you're looking for, but I ran across [this answer](http://stackoverflow.com/a/4925842/715075) while wondering how `CorrelationManager.ActivityId` did the same thing in WCF requests. That might put you onto something fruitful. – anton.burger Jan 20 '12 at 14:07

2 Answers2

3

In fact, I'll make my comment an answer and point you at Jeffrey Richter.

The CallContext class gives you the ability to store data for a "logical execution path", which can cross threads and AppDomains.

anton.burger
  • 5,637
  • 32
  • 48
2

Just adding more info for shambulator answer.

CallContext.GetLogicalData and CallContext.SetLogicalData do the trick

Ori Calvo
  • 426
  • 5
  • 6