Another Thread Safety Question

G

Guest

Hypothetical question:

A multi-threaded app has an object with a privately scoped collection (like
ArrayList) that is shared between threads. The model is one thread
creates/reads/writes/updates the collection, and all other threads read the
collection. What are the minimal locks required for thread safety?

Is it safe to only lock access when writing/updating the collection?

Is it overkill to lock access for all access (including shalllow-copy
instance cloning and read-only) in the properties/methods exposed by this
object?
 
P

Peter Duniho

[...] What are the minimal locks required for thread safety?

Is it safe to only lock access when writing/updating the collection?

Is it overkill to lock access for all access (including shalllow-copy
instance cloning and read-only) in the properties/methods exposed by this
object?

Well, the question of the least-costly method of locking is a whole other
level of writing thread-safe code.

That said, consider that if you are writing to the data, you cannot
reliably read the data until the writing is done. Thus, locking for
writing requires that reads are locked too.

You can safely read from multiple threads simultaneously, but you will run
into the problem that readers still need to lock the data somehow, so that
the data doesn't get modified during reads.

How best to do this is a subject for a much more detailed discussion,
probably served better by more in-depth articles or books on the topic.

Pete
 
G

Guest

Thank you Pete. That makes perfect sense to me. In order to convince my
co-workers, what books(s) would you reccommend that I use to prove this
point? Also, I did not see another Microsoft monitored .Net newsgroup dealing
with threading issues... did I miss something?

-Roy
 
J

Jon Skeet [C# MVP]

You can safely read from multiple threads simultaneously, but you will run
into the problem that readers still need to lock the data somehow, so that
the data doesn't get modified during reads.

While it's not *dangerous* to read from multiple threads, even if
you're reading a single int (which is guaranteed to be changed
atomically) you need to lock, use a memory barrier, or use a volatile
variable to make sure that the read actually sees the most recent
value, rather than a potentially previously read one.

See http://pobox.com/~skeet/csharp/threads/volatility.shtml

(Unfortunately there are various ways in which the .NET memory model is
very poorly specified, but such is life.)
 
P

Peter Duniho

Thank you Pete. That makes perfect sense to me. In order to convince my
co-workers, what books(s) would you reccommend that I use to prove this
point? Also, I did not see another Microsoft monitored .Net newsgroup
dealing with threading issues... did I miss something?

Sorry, can't help you on either front. As far as I know, there is not any
newsgroup specific to threading, though there are Windows programming
newsgroups that are probably more technical than this one and so might be
able to offer better advice. Of course, general threading advice for
native Win32 threads may or may not apply to .NET threads...I'm not
exactly an expert on the exact differences between the two with respect to
how data is managed and stored (though I gather that most of the time,
there's not any practical difference).

As far as books go, I don't have any idea. I've never read a book on
Windows programming, so can't recommend anything specific. Maybe other
people will have suggestions.

In any case, I would think it pretty much obvious that since there's no
automatic mechanism to prevent one thread from writing to memory while
another thread is reading from the same area, that readers need to lock or
synchronize with writers. On a single CPU system, if the data you're
dealing with is a single processor word, then a read or write operation is
atomic and you can get away without synchronization, but that's a very
narrow scenario (and as Jon points out, you still need to make the effort
to ensure that the two threads are really accessing the same location, by
marking the variable as volatile). Other than that, there's simply no
guarantee of serializing access to data across threads. I'm not sure you
should need a book to point this out to others. :)

Pete
 
G

Guest

Don't reinvent the wheel... Use the static member 'Synchronized' to get a
thread-safe collection instance. For instance:
Queue myQueue = Queue.Synchronized(new Queue());



Regards,
Fredrik
 
J

Jon Skeet [C# MVP]

Don't reinvent the wheel... Use the static member 'Synchronized' to get a
thread-safe collection instance. For instance:
Queue myQueue = Queue.Synchronized(new Queue());

That's fine for single reads/writes, but is no good if a thread does
something like iterating over the collection - at that point, a lock
needs to be obtained for the whole iteration process, to prevent the
collection being modified while iterating.

Personally I dislike the Synchronized method precisely because it sort
of implies that using a "synchronized" version means you can ignore
all threading issues. It doesn't - it just means you need to worry
about the subtle ones instead of subtle and obvious ones...

Jon
 
B

bazad

Last time I had to synchronize access to a collection I simply used locked
on its SyncRoot.
 
J

Jon Skeet [C# MVP]

Last time I had to synchronize access to a collection I simply used locked
on its SyncRoot.

Yes - doing that consistently is better, IMO, than using Synchronized
and then working out where you *also* need locking.
 

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