The .NET library provides sufficient thread support that you will rarely find yourself: creating your own threads and managing synchronization manually.
Thread synchronization can be tricky, especially in complex programs. If you do decide to create your own threads, you must confront and solve all the traditional problems of thread synchronization, such as race conditions and deadlock.
A race condition
exists when the success of your program depends on the uncontrolled
order of completion of two independent threads.
Suppose, for example, that you have two threads—one is responsible for opening a file and the other is responsible for writing to the file. It is important that you control the second thread so that it’s assured that the first thread has opened the file. If not, under some conditions the first thread will open the file, and the second thread will work fine; under other unpredictable conditions, the first thread won’t finish opening the file before the second thread tries to write to it, and you’ll throw an exception (or worse, your program will simply seize up and die). This is a race condition, and race conditions can be very difficult to debug.
You cannot leave these two threads to operate independently; you must
ensure that Thread1
will have completed before
Thread2
begins. To accomplish this, you might
Join( )
Thread2
on
Thread1
. As an alternative, you can use a
Monitor
and Wait( )
for the
appropriate conditions before resuming Thread2
.
When you wait for a resource to become free, you are at risk of
deadlock
, also called a deadly
embrace.
In a deadlock, two or more threads
are waiting for each other, and neither can become free.
Suppose you have two threads, ThreadA
and
ThreadB
. ThreadA
locks down an
Employee object and then tries to get a lock on a row in the
database. It turns out that ThreadB
already has
that row locked, so ThreadA
waits.
Unfortunately, ThreadB
can’t update the row
until it locks down the Employee
object, which is
already locked down by ThreadA
. Neither thread can
proceed, and neither thread will unlock its own resource. They are
waiting for each other in a deadly embrace
.
As described, the deadlock is fairly easy to spot—and to
correct. In a program running many threads, deadlock can be very
difficult to diagnose, let alone solve. One guideline is to get all
the locks you need or to release all the locks you have. That is, as
soon as ThreadA
realizes that it can’t lock
the Row
, it should release its lock on the
Employee
object. Similarly, when
ThreadB
can’t lock the
Employee
, it should release the
Row
. A second important guideline is to lock as
small a section of code as possible and to hold the lock as
briefly as possible.
18.117.189.228