synclock questions

K

Keith Langer

I have some questions about whether synclock is necessary in a few
different scenarios:

1) I have a Queue class which is shared between two threads. Thread 1
pushes objects onto the queue and Thread 2 pops objects off the queue
one at a time (with no enumerators - just first in, first out). Does
the Queue class need to be synclocked when objects are pushed on or
popped off?

2) I have a boolean variable which can be read or written by Thread 2,
but is read-only to Thread 1. Does this variable need to be
synclocked when it is read by either thread or changed by thread 2?

thanks,
Keith
 
T

Tom Shelton

I have some questions about whether synclock is necessary in a few
different scenarios:

1) I have a Queue class which is shared between two threads. Thread 1
pushes objects onto the queue and Thread 2 pops objects off the queue
one at a time (with no enumerators - just first in, first out). Does
the Queue class need to be synclocked when objects are pushed on or
popped off?

Unless the queue is syncronized, then yes - you'll want to lock access
on the push and pop.
2) I have a boolean variable which can be read or written by Thread 2,
but is read-only to Thread 1. Does this variable need to be
synclocked when it is read by either thread or changed by thread 2?

Again, yes. If a value is readonly this isn't a problem, but when it is
being written by one thread and read by another, there is always a
chance of a context switch which may leave a shared variable in an
invalid state.
 
J

Jay B. Harlow [MVP - Outlook]

Tom,
Again, yes. If a value is readonly this isn't a problem, but when it is
being written by one thread and read by another, there is always a
chance of a context switch which may leave a shared variable in an
invalid state.
I would say, maybe or no. As a boolean is an atomic value (32bits or less)
one thread is "guaranteed" by the CLR to be able to read the value or write
the value without another thread "corrupting" that value.

At least that is the way I read the Class Library Design Guidelines.

http://msdn.microsoft.com/library/d...enref/html/cpconThreadingDesignGuidelines.asp

I don't have a reference on atomic values & threads in the CLR itself handy.

I would be more concerned if thread 2 need to read & modify the value &
thread 1 should wait during the read & modify cycle.

Hope this helps
Jay
 
T

Tom Shelton

Tom,
I would say, maybe or no. As a boolean is an atomic value (32bits or less)
one thread is "guaranteed" by the CLR to be able to read the value or write
the value without another thread "corrupting" that value.

At least that is the way I read the Class Library Design Guidelines.

http://msdn.microsoft.com/library/d...enref/html/cpconThreadingDesignGuidelines.asp

I don't have a reference on atomic values & threads in the CLR itself handy.

I would be more concerned if thread 2 need to read & modify the value &
thread 1 should wait during the read & modify cycle.

Hope this helps
Jay

Jay,

you are correct. In this case there is no chance of corruption,
but there is still a chance of syncronization problems in the larger
scheme of things. But reading his situation again, it may not be needed
in this case because one thread is reading and the other writing. But,
if he is doing any kind of read & modify, as you said, he will want to
sync those sections of code.

Threading is a powerful tool - but still very complex. One day, I hope
to truely understand it :)
 
K

Keith Langer

Thanks guys.

Is 32 bits the magic limit for atomic values which wouldn't require a
synclock? Would I need to use a synclock on a 64 bit long? A date?
Would strings of any length need to be synclocked?

Keith
 
J

Jay B. Harlow [MVP - Outlook]

Keith,
Is 32 bits the magic limit for atomic values which wouldn't require a
synclock?
Yes for value types.
Would I need to use a synclock on a 64 bit long?
Yes as its not 32 bits.
Yes as its underlying type is 64 bits
Would strings of any length need to be synclocked?
Remember that a string is an immutable reference type, because it is an
immutable reference type synclock is not needed, Actually because it is a
reference type synclock is not needed to change the reference itself. If you
have a mutable reference type, you may want to consider using synclock when
changing the state of the object the reference refers to, not specifically
the reference itself.

Hope this helps
Jay

Keith Langer said:
Thanks guys.

Is 32 bits the magic limit for atomic values which wouldn't require a
synclock? Would I need to use a synclock on a 64 bit long? A date?
Would strings of any length need to be synclocked?

Keith
 
K

Keith Langer

Jay,

I am using queues to pass messages between threads, and I'm wondering if
it would be better to pass changes to these variables which would
require a synclock through the queue instead.

That way if I had to set or get the value of a date, I could avoid
synclocks entirely. Do you think this is overkill?

From what I've found and what you've told me, I can avoid synclocks on
boolean, int32 and string types if only one thread can modify the
values. Now why exactly is it that I must use synclocks if both threads
can modify those values? Wouldn't it be impossible for more than one
thread to modify one of these values at a time?

Keith
 
K

Keith Langer

Jay,

Do I need to use synclocks on reads or just on writes? For instance, if
I have get/set properties on a date object, do I just use synclocks on
the set property?

Keith
 
T

Tom Shelton

Jay,

Do I need to use synclocks on reads or just on writes? For instance, if
I have get/set properties on a date object, do I just use synclocks on
the set property?

Keith

On a date, because it is not a 32-bit value, you'll need it on both. Since
this is a 64-bit value, the read and write are not guarenteed to be
atomic. That means, a task switch is possible while the write is going
on, leaving the data in an invalid state and possible data corruption...

Also, if this is a situation with a multiple readers and a single
writer, you may want to look at System.Threading.ReaderWriterLock... It
is an locking mechanism optimized for the multiple reader/single writer
scenario.
 
K

Keith Langer

So you're saying that in the 64 bit case, even though I have only one
writer thread, a synclock on the writer thread is not enough since it
could begin a write operation while another thread is doing a read
operation?

The ReaderWriterLock class sounds like it could come in handy. However,
I believe that only two threads will be accessing the variable - one
with read/write access and the other with read access. I assume that
the writer thread does not require a synclock when reading since no
other thread will be writing.

One alternative I've considered is to use a queue as a moderator and
then have the writer pass value updates through the queue (I think I
mentioned this earlier in this thread). I was wondering if this sounded
like a good idea or overkill.

I could also try storing the date as a string and then casting it as a
date in the property Get - then I don't think I'd need to do any locks.
Any thoughts?
 
T

Tom Shelton

So you're saying that in the 64 bit case, even though I have only one
writer thread, a synclock on the writer thread is not enough since it
could begin a write operation while another thread is doing a read
operation?

Exactly, because the operation is not guarenteed to be atomic... Unless
the reader and writer both sync on the same object, there is no way for
the reader thread to know that the write operation is in progress.
 
J

Jim Shoo

Keith,

First of all, always remember the KISS principal. If you don't know
what this is then I suggest you look it up and always keep it in mind
when programming.

Now, according to the .NET help files, ALL OPERATIONS (including Count
property) are not thread safe when using instance members. With this
said, I would wrap the County property in a synclock or a
ReaderWriterLock. If you use a ReaderWriterLock make sure you call the
release lock functions in a finally statement when you are done.
Otherwise you could block your entire application.

This is from the help files
"Instance members are not guaranteed to be thread-safe. To guarantee
the thread safety of the Queue, all operations must be done through
the wrapper returned by the Synchronized method."

Regards,
 
J

Jay B. Harlow [MVP - Outlook]

Keith,
In addition to the others comments:
From what I've found and what you've told me, I can avoid synclocks on
boolean, int32 and string types if only one thread can modify the
values. Now why exactly is it that I must use synclocks if both threads
can modify those values? Wouldn't it be impossible for more than one
thread to modify one of these values at a time?
If two threads wrote to a common value, the last thread to write would be
the value in that thread. However are the threads incrementing this common
value? If they are incrementing the value then you have a "unit of work" a
read followed by a write. If both threads read the value when it was 10,
thread one would write 11, and thread two would also write 11, if both
threads are suppose to increment the value, clearly it should be 12 after
both threads increment the value! Hence you need proper thread locking!

Don't confuse atomic values with atomic operations. An integer is an atomic
value, in that it can be read or written with out fear of a task switch,
however operations such as adding one to an integer "x += 1" are not atomic!
Remember to increment an integer, you have a read, followed by an add,
followed by a write. A task switch can occur between any of the three
operations.

My number one rule with multi-threaded apps is to use proper Locking! (which
means even for atomic values, most of the time I use thread locking!) It may
be overkill, however I know its safe! As invariable even on simple integer
values the "unit of work" is more then just a single read or a single write,
and often more then one "simple integer" is involved! Note for "simple
integers" I would consider using the Interlocked class described below
instead of a SyncLock.

My second rule is to encapsulate that locking into the object itself, do not
rely on locking external to the object itself. If you are a follower OOP
this one makes sense, if you don't follow OOP this one may be hard to
explain. Which means that "simple integers" would not be "global" variables,
they would be encapsulated in another class with methods that had the proper
locking for that class. By encapsulating the locking in the class you are
ensured that all access following the same locking rules!

A third rule is to not lock on the object itself or even more important lock
on a Type. Create a New Object (literally New Object) as a padlock and use
that.

Private Readonly m_padlock As New Object ' class scope

SyncLock m_padlock
m_value = value
End SyncLock

SyncLock me ' bad!
SyncLock GetType(HashTable) ' bad!

By creating a padlock that is encapsulated in your class you are ensured
that only you are locking on it, and you are not blocking other threads
unnecessarily!
That way if I had to set or get the value of a date, I could avoid
synclocks entirely. Do you think this is overkill?
As I implied above, when dealing with multi-threading apps, proper thread
safety is NEVER overkill! For the most part I do not "avoid" locking if I
know a variable is "atomic", as its too easy to change that variable later
(an Integer to a Long) and suddenly have obscure problems later. In other
words its better safe then sorry!

By thread safety I mean using a SyncLock or one of the other thread locking
mechanisms in the System.Threading namespace. Remember most collections in
System.Collections have a Synchronized method that returns a thread safe
collection, which allows you to get a thread safe Queue for example, and you
don't need to manually protect all of its methods. However if I have a Queue
that is already encapsulated in one of my other classes, I may consider
making my class thread safe (via ReaderWriterLock for example) instead of
using Queue.Synchronized to make a thread safe Queue. The methods on my
class would hide all the details of the thread safety! Also if you are using
CollectionBase or DictionaryBase (which I normally do) you will need to add
your own thread safety. Also by encapsulating the locking in the class
itself I can introduce a ResetEvent (either auto or manual) that will allow
the consumer thread (reader) to "go to sleep" until the producer thread
(writer) is ready for it. Which is more efficient then having one thread
spinning its wheels until the Queue.Count is not zero.

Understand that a SyncLock is implemented in terms of the
System.Threading.Monitor class, most of the time its easier to use the
SyncLock statement instead of the Monitor class.

Some higher forms of locks in the System.Threading namespace are:
- AutoResetEvent
- ManualResetEvent
- Mutex
- ReaderWriterLock

The Interlocked class has a number of shared thread safe methods for dealing
with "atomic" values. I would use this class before

Hope this helps
Jay
 

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

Similar Threads

Synclock Questions 2
Question about Synclock and exceptions 3
SyncLock 4
Synclock blocking order 1
SyncLock and Array.SyncRoot and ReDim 2
Shared Variable used as SyncLock 1
Synclock 1
Thread Sync Queue Problem 2

Top