Does threadpool utilize a memory barrier?

G

Guest

It occurs to me that if I have a work object that gets executed via
QueueUserWorkItem AND the work proc accesses only that object's
instance data I STILL may have to lock because the object constructor
ran in a different thread. That therefpre means that without a lock
the threadpool thread might not get the correct view of the instance
data. (Specifically, it might still be seen as null).

Has this ever come up before?

Thanks,
Tom
 
N

Nicholas Paldino [.NET/C# MVP]

Tom,

No, it has not. An object can not be accessed in a constructor by any
other thread BUT the thread that the object is being constructed on.

If you are assigning the object to a field that is shared by two
different methods in the ThreadPool, then yes, it is possible. However, you
should encapsulate access to the field in a property, which will guarantee
that you have only one instance (it will lock on something, check to see if
null, and create the instance if necessary).

Hope this helps.
 
J

Jon Skeet [C# MVP]

It occurs to me that if I have a work object that gets executed via
QueueUserWorkItem AND the work proc accesses only that object's
instance data I STILL may have to lock because the object constructor
ran in a different thread. That therefpre means that without a lock
the threadpool thread might not get the correct view of the instance
data. (Specifically, it might still be seen as null).

Has this ever come up before?

Yes, it's been asked, and to be honest there isn't a satisfactory
answer. I very, very much doubt that the thread-pool is able to work
without there being a memory barrier involved somewhere - after all,
the delegate itself has to be passed between threads, so there must be
*some* synchronization. Having said that, the documentation doesn't
specify it.
 
D

Daniel O'Connell [C# MVP]

Jon Skeet said:
Yes, it's been asked, and to be honest there isn't a satisfactory
answer. I very, very much doubt that the thread-pool is able to work
without there being a memory barrier involved somewhere - after all,
the delegate itself has to be passed between threads, so there must be
*some* synchronization. Having said that, the documentation doesn't
specify it.

Just to add on: Since the documentation and specification, to my knowledge
anyway, don't define it, you really should ensure *your* code is safe.
Without a specificiation I could see subtle issues coming up across
platforms or implementations.
 
G

Guest

Nicholas,

You stated:

"If you are assigning the object to a field that is shared by two
different methods in the ThreadPool, then yes, it is possible."

That is not really what I was trying to describe, so I apologize for
not being more clear. Let me restate the problem.

An object "worker" is created on thread "A". That is to say, its
constructor is called on thread "A", with args X, Y, and Z getting
passed in. Aside from the constructor, thread "A" never accesses the
"worker" again. Now the "worker" is invoked via the threadpol
(QueueUserWorkItem) on thread "B". Now even though thread "B" is the
only one to access the data from now on in this stand-alone worker
object, technically the data was assigned via the constructor that
obviously ran on a different thread. So we have a potentional
threading issue right?

Put yet another way, it is *impossible* to create a worker object to be
executed on the framework threadpool without obviously creating it on a
seperate thread. So it seems that one use locking when using the
threadpool even if only the thread from the threadpool performs
operations/etc on the work data.

Thanks,
Tom
 
G

Guest

Jon and Daniel,

Thanks for your help. It seems to me there must be at least a dozen
bad examples of using the ThreadPool on the MSDN if we must use locking
in this case.

Next question, is it sufficient to just lock once in the constructor
and once at the start of the threaded work proc to have the proper
flushes occur on the memory cahce of the two threads involved? It
seems wasteful to reaquire the lock over and over in the work procdure
once the values are in a know good state.

Thanks again,
Tom
 
N

Nicholas Paldino [.NET/C# MVP]

Tom,

You don't have an issue here with worker being created on thread A.
Once you create the object, if you pass it to another object, there is no
affinity to the thread it was created on (unless you impose one, like
Controls in Windows Forms). It's just another object.

What you do have to worry about is X, Y, and Z. If you store those in
the class and call them, the calls are coming in from another thread, and
access to them has to be synchronized (either by you, or the instances
themselves).

Other than that, you shouldn't have a problem. Since that instance will
only be accessed in the thread pool, you don't have to worry about other
fields you have (besides the fields that X, Y, and Z are assigned to).
 
N

Nicholas Paldino [.NET/C# MVP]

Tom,

The constructor is only accessed by one thread, ever. In this sense,
you never have to use lock in the constructor. If you are using lock in the
constructor, you are going to lock on something other than your internal
state (since you created it, and you can't lock on this, because "this"
could not have been possibly assigned somewhere else to be used as a lock
either), and it is better to have something else managing the locks to that
(encapsulate it).
 
J

Jon Skeet [C# MVP]

Nicholas Paldino said:
The constructor is only accessed by one thread, ever. In this sense,
you never have to use lock in the constructor. If you are using lock in the
constructor, you are going to lock on something other than your internal
state (since you created it, and you can't lock on this, because "this"
could not have been possibly assigned somewhere else to be used as a lock
either), and it is better to have something else managing the locks to that
(encapsulate it).

"this" can certainly be used in other threads while the originally
constructing thread is running - for instance if the constructor
creates a thread and starts it during the constructor.
 
J

Jon Skeet [C# MVP]

Thanks for your help. It seems to me there must be at least a dozen
bad examples of using the ThreadPool on the MSDN if we must use locking
in this case.

Next question, is it sufficient to just lock once in the constructor
and once at the start of the threaded work proc to have the proper
flushes occur on the memory cahce of the two threads involved? It
seems wasteful to reaquire the lock over and over in the work procdure
once the values are in a know good state.

You need a memory barrier after you've made the last change in the
thread "providing" the value, and a memory barrier before you access
any other data in the thread "consuming" the value. You only need to do
it once.
 
B

Brian Gideon

Tom,

Just so we're all on the same page I assume your question can be better
undersood by considering the following example:

class Test
{
private static object someObject = null;

static void Main()
{
someObject = new Object();
ThreadPool.QueueUserWorkItem(new WaitCallback(WorkItem));
Console.ReadLine();
}

static void WorkItem(object state)
{
if (someObject == null)
{
// Could this really happen?
Console.WriteLine("Foo");
}
else
{
Console.WriteLine("Bar");
}
}
}

The question is whether or not the write to someObject will be seen by
the WorkItem method right? Is it possible that "Foo" could be written
to the console?

I agree with Jon, I think it's very likely that the ThreadPool creates
a memory barrier internally and thus "Foo" would never be written.

Brian
 
G

Guest

*** Inlined ***

"You need a memory barrier after you've made the last change in the
thread "providing" the value, "

*** Hence the lock in the constructor, since that is right after the
last change, as you asy "providing the value". ***

"and a memory barrier before you access
any other data in the thread "consuming" the value. You only need to
do
it once. "


*** Hence the second half of my idea to lock once at the start of my
work proc ***

*** And just to be clear, I know that no other thread is going to touch
the data while I'm in the constructor. The point of the lock in the
constructor is just to create a memory barrier. The same for the lock
at the start of the work proc. It just forces a memory barrier.

Given the originaly advice of using locking since the docos don't say
there is a memroy barrier, my current goal is to NOT lock on every
access of the data since I know that no other thread will ever touch
the work data once I begin processing. What I'd like to know is if I
can accomplish this goal by using just two locks instead of thousands
(if I access those variables via locked properties during the work
procedure).

Tom
 
G

Guest

Brian,

This is a bit closer, but your example is about right.


class Worker
{

// test kicker
static void Main()
{
arg = new Object();
worker = new Worker(arg);
ThreadPool.QueueUserWorkItem(new WaitCallback(worker.Process));
Console.ReadLine();
}

// instance data
private object someWorkData;

public Worker(object arg)
{
someWorkData = arg;
}


public void Process(object state)
{
if (someWorkData == null)
{
// Could this really happen?
Console.WriteLine("Foo");
}
else
{
Console.WriteLine("Bar");
}

while (true)
{
// use someWorkData over and over...
}

}

}
 
G

Guest

To be specifc, this example locks twice, just as you implied was
needed. Is this the bare minimum I need to be threadsafe in the
thread-pool situation?

class Worker
{

private object m_Lock = new object();

// instance data
private object someWorkData;

public Worker(object arg)
{
// lock here just for a memory barrier
lock(m_Lock)
{
someWorkData = arg;
}
}

public void Process()
{

object localArg;

// lock here just for a memory barrier
lock(m_Lock)
{
localArg = someWorkData;
}

while (true)
{
// use slocalArg over and over...
}

}

}
 
G

Guest

Nicholas,

It is specifically X, Y, and Z that I am asking about.

1. Do I need to protect X, Y, and Z or is there a memory barrier.

2. If there is no memory barrier in play, then I'd like to NOT lock on
each access of these three fields over and over again because I know
that (aside from when they were passed in during construction) the only
thread that touches them is the worker thread.

Thanks!
Tom

PS - As an aside, I've been told that a thread start has an implicit
memory barrier (which is good to know) but I'd like to know were to
specifically look to learn this kind of detail. The standard .NET
docos don't mention such details as that (or such details as my
original question) and usually like to do such research myself instead
of bothering you fine people :)
 
J

Jon Skeet [C# MVP]

Given the originaly advice of using locking since the docos don't say
there is a memroy barrier, my current goal is to NOT lock on every
access of the data since I know that no other thread will ever touch
the work data once I begin processing. What I'd like to know is if I
can accomplish this goal by using just two locks instead of thousands
(if I access those variables via locked properties during the work
procedure).

Yes, that should be fine.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top