Prev: MemberInfo derived classes
Next: IComparer
From: Peter Duniho on 14 Jun 2010 11:37 UFO wrote: > i don't get it. why does it called 'static' ? Because it's applicable only to static members. But that doesn't mean you can't build data storage that's per-instance on top of that. You just need an object that can map an instance to some specific data, and then reference per-thread instances of that object in the static member. An example of such an object would be a dictionary. > also, does each instance garbage collected as soon as it is not referenced > (per thread) ? Since the static member is no longer present when the associated thread no longer exists, everything it refers to is no longer reachable and can be garbage-collected. > and please, please give me an example of how it works. Unfortunately, I don't have time to write a code sample now. Hopefully the above is sufficient for you to understand the mechanism of how per-instance, per-thread data storage would work using only the original thread-local API in .NET. Pete
From: UFO on 17 Jun 2010 18:48 about the dictionary example, i don't get what is has to do with concurrency and threads. about static members, i still think that its name is misleading, since static means that it can always be accessible and that there is only one instance of it through the whole running time of the program.however, 'static' is also a misleading keyword on Java, since there you have a static class, which is a very weird thing to have as a name for an inner class.on C# , static clsss means it's like a Singleton , which is a little more obvious. about the ThreadLocal (or static thread member ) , will it be garbage collected as soon as the thread finishes its running? if so, will an inner function of the thread (if i choose to extend the thread) be able to reach such a member? or maybe threads cannot be extended (derived) just because of this? about a code example, you can copy and paste the one i gave, and change what is needed to be changed.
From: Peter Duniho on 18 Jun 2010 01:41 UFO wrote: > about the dictionary example, i don't get what is has to do with concurrency > and threads. Because if you want per-instance thread-local data prior to .NET 4, you need some mechanism to use the static-variable feature that exists to implement an instance-variable feature that doesn't exist. A dictionary isn't required, but it's the most obvious approach. > about static members, i still think that its name is misleading, since > static means that it can always be accessible and that there is only one > instance of it through the whole running time of the program.however, > 'static' is also a misleading keyword on Java, since there you have a static > class, which is a very weird thing to have as a name for an inner class.on C# > , static clsss means it's like a Singleton , which is a little more obvious. The keyword "static" is being used in your code example in pretty much the same way it's used in C#, with the exception of the static nested class (which C# doesn't have the concept of...or rather, all nested classes in C# are static nested; there are no inner classes). So, no…in this case the word is not misleading at all. It's doing exactly what one would expect even coming from C#, with the exception of your static nested class. In fact, since all your code involves static members, the [ThreadStatic] attribute that has been around since .NET 1.0 is fine for the needs of that sample. > about the ThreadLocal (or static thread member ) , will it be garbage > collected as soon as the thread finishes its running? if so, will an inner > function of the thread (if i choose to extend the thread) be able to reach > such a member? or maybe threads cannot be extended (derived) just because of > this? I don't know what you mean by "inner function". Even in Java, that's not a defined term. The System.Threading.Thread class is in fact sealed, so whatever question you're asking with respect to inheriting (derived) classes, the answer must be "you can't do that", because you can't inherit System.Threading.Thread. With respect to garbage collection of ThreadLocal, an instance of ThreadLocal will follow the same rules as any other object. It's a single instance, and will only be garbage collected when it's not reachable at all. Note that when using ThreadLocal, all threads will access the same instance of the object. The thing that makes it per-thread is that the Value and IsValueCreated properties access data storage that is specific to each thread. So, if you are storing a reference type in the ThreadLocal object, when the thread for a Value of that reference type no longer exists, then in theory that Value for that thread is no longer reachable, even though the ThreadLocal object itself is still reachable and could be eligible for garbage collection. > about a code example, you can copy and paste the one i gave, and change what > is needed to be changed. I don't think copy/paste of Java code is going to help much. But here are some examples of how you might have thread-local storage, static and per-instance (warning: uncompiled, untested code…I apologize in advance for any silly typos or minor structural defects, but the basic idea should be correct): // Using static member, only provides static // thread-local data public class ThreadID { private static volatile int nextID = 0; [ThreadStatic] private static int threadID = Interlocked.Increment(ref nextID); public static int get() { return threadID; } public static void set(int index) { threadID = index; } public static void reset() { nextID = 0; } public static int getNumberOfRegisteredThreads() { return nextID; } } // Using static dictionary to implement per-instance // thread-local data public class ThreadID { private static volatile int nextID = 0; [ThreadStatic] private static Dictionary<ThreadID, int> _dictThreadID = new Dictionary<ThreadID, int>(); public ThreadID() { _dictThreadID.Add(this, Interlocked.Increment(ref nextID)); } public int get() { return _dictThreadID[this]; } public void set(int index) { _dictThreadID[this] = index; } public static void reset() { nextID = 0; } public static int getNumberOfRegisteredThreads() { return nextID; } } // Using ThreadLocal class to implement per-instance // thread-local data (.NET 4.0 only) { private static volatile int nextID = 0; private static ThreadLocal<int> threadID = new ThreadLocal<int>(); public ThreadID() { threadID.Value = Interlocked.Increment(ref nextID); } public int get() { return threadID.Value; } public void set(int index) { threadID.Value = index; } public static void reset() { nextID = 0; } public static int getNumberOfRegisteredThreads() { return nextID; } } Hope that helps. Pete
From: Peter Duniho on 18 Jun 2010 01:46 And speaking of structural defects… Peter Duniho wrote: > [...] > // Using ThreadLocal class to implement per-instance > // thread-local data (.NET 4.0 only) > { > private static volatile int nextID = 0; > private static ThreadLocal<int> threadID = new ThreadLocal<int>(); Of course, for "threadID" to store data per-instance, it must be an instance variable, not "static" as I've declared above. Sorry for the mistake.
From: Peter Duniho on 18 Jun 2010 02:27
Okay, one more try (I did warn that the code hadn't been compiled, never mind tested :) )… Anyway, both of the per-instance examples I posted have a fundamental flaw in that they initialize the value only for the thread where the instance is created. Other threads won't have values when they attempt to read the per-instance thread-local value. Here are fixed versions: // Using static dictionary to implement per-instance // thread-local data public class ThreadID { private static volatile int nextID = 0; [ThreadStatic] private static Dictionary<ThreadID, int> _dictThreadID = new Dictionary<ThreadID, int>(); public int get() { int i; if (!_dictThreadID.TryGetValue(this, out i)) { i = Interlocked.Increment(ref nextID); _dictThreadID.Add(this, i); } return i; } public void set(int index) { _dictThreadID[this] = index; } public static void reset() { nextID = 0; } public static int getNumberOfRegisteredThreads() { return nextID; } } // Using ThreadLocal class to implement per-instance // thread-local data (.NET 4.0 only) { private static volatile int nextID = 0; private ThreadLocal<int> threadID = new ThreadLocal<int>(() => Interlocked.Increment(ref nextID)); public int get() { return threadID.Value; } public void set(int index) { threadID.Value = index; } public static void reset() { nextID = 0; } public static int getNumberOfRegisteredThreads() { return nextID; } } Note that in both cases, the value is not initialized until the first access. This means that the int ID returned may or may not correlated to the order in which any thread was created, depending on when the ID value is actually retrieved or set. Of course, since a per-instance value isn't really correlated per-thread anyway (for any given thread, there will be N unique IDs where N is the number of instances of ThreadID created), this shouldn't be much of an issue. The main point here is to show how the techniques work. I _believe_ that I have finally worked out the wrinkles in the examples I posted. But I'm still too lazy to actually compile and run the code at the moment, so if there are still problems, I do apologize for that. :) Pete |