Yes, that makes more sense. Here's the deal and a few things to
consider...
Usually you want to avoid making instance members of your public
classes thread-safe. That's because some users of your library may not
be using it in a multithreaded environment and those that do will have
to enforce their on synchronization on your classes. That makes your
job easier. That's how most of the .NET base class library is
designed.
Of course that doesn't help with your library's own internal
thread-safety requirements. And you're right. Users of your library
shouldn't have to worry or even know that it is using other threads
behind the scenes whether or not you decide to make the public
interface thread-safe or not.
One strategy for dealing with this is to make your objects immutable.
The only way your threads can modify data is if they create new copies
of it. Once they have completed whatever lengthy calculation was
required to create the new data the public references would be swapped
out (in a thread-safe manner of course). Do you see how that
eliminates a lot of the complexity? The string data type in .NET,
although a reference type, is immutable. That's why it is inherently
safe to access and modify it from multiple threads.
Another strategy that might work for you is to copy any data structures
the threads will use before you kick them off. That way the threads
will be working with private copies while the original public copies
are still valid. After the threads finish their work swap the public
references out (again, in a thread-safe manner) to publish the new
data.
Both approaches have a similar theme. That is they both work by making
sure the public data structures and the data structures the threads are
working with are separate. That requires less synchronization which
makes things easier for you. They both have a similar caveat though.
How do callers of your library know when the data structures have been
updated? How much extra work is required to repeatedly make separate
copies and publish the updates? Would these strategies have unexpected
side effects to the callers of your library? You'll need to have
answers to those questions.
public class Example
{
private SomeObject foo = new SomeObject();
private Object lockObject = new Object();
public SomeObject Foo
{
get
{
lock (lockObject)
{
return foo;
}
}
}
// This method might be invoked by another thread.
private void ChangesFooAsynchronously()
{
// Copy the data structure.
SomeObject copy;
lock (lockObject)
{
// This must be a deep copy.
copy = foo.Clone();
}
// We can safely access the copied data structure here.
copy.ChangeMe();
copy.ChangeMeAgain();
// Now publish the result.
lock (lockObject)
{
foo = copy;
}
}
}
Brian
bonk wrote:
Consider the following scenario: I am writing an API for others to use. It
has some public classes that expose some some fields as public (via property
acessors) or as protected (as fields directly) and they therefore can be
freely acessed by the user of my class (either by instanciating or deriving
from that class). Now inside some internal methods of these public classes
of my API I have to work with those fields using threads over a longer time.
So my goal is now to prohibt access to those public or protected fields
while one of my internal threads is doing some work with them. The problem
here:
The users of my class can not and should not have to know that they have to
aquire a lock to some sort of objects if they want to read or write from/to
those fields. I would like to abstact that away from the API view. Rather I
would like my API users automatically (whether they spawned their own thread
or wether they are on the main thread) to be forced to wait until my thread
is done and access is allowed again.
Hope that makes sense ...