From: Peter Duniho on
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
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
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
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
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
First  |  Prev  | 
Pages: 1 2 3
Prev: MemberInfo derived classes
Next: IComparer