threads in .net and protecting shared variables

  • Thread starter Thread starter Claire
  • Start date Start date
C

Claire

I was ok understanding threads in Delphi pre .net, but reading through a
reference book and comparing it to what help file says has confused me

A System.Threading.Timer thread in one class calls an event in a 2nd class
as follows (fast timer)

public void OnDriverSendResult(rackdetail RackDetail)
{
// Add new RackDetail to linked list and leave quickly
RackDetail.Previous = this.LastDetail;
if (this.LastDetail == null)
this.FirstDetail = RackDetail;
else
this.LastDetail.Next = RackDetail;
this.LastDetail = RackDetail;
}

In the 2nd class, I will have another system.threading.timer thread (slow
timer) that takes the linked list created by the first timer, processes the
data in it and posts it to a database.

private void ProcessList()
{
if (FirstDetail == null) return;

RackDetail Unprocessed = FirstDetail;
FirstDetail = null;
Processed = Process(Unprocessed);
Post(Processed);
}

How do I protect shared variables/objects in .net threads please. Some code
samples would be more useful to me in the first instance.

thanks
Claire
 
Take a look at Monitor/Enter/Exit and lock(which uses Monitor
internally) to do synchronization. This is similar to Critical Section
in Win32. Another option to synchronize data is to use WaitHandle
derived classes, Mutex, ManualResetEvent and AutoResetEvents.
 
Ajay said:
Take a look at Monitor/Enter/Exit and lock(which uses Monitor
internally) to do synchronization. This is similar to Critical Section
in Win32. Another option to synchronize data is to use WaitHandle
derived classes, Mutex, ManualResetEvent and AutoResetEvents.

Or, use "lock", which is inherently exception-safe and (in this case)
pretty easy to read and understand.

You do realize that your OnDriverSendResult is not re-entrant -- even on
it's own?

You seem to be using a self-implemented linked list, why not use one of
the supplied data-structures in .NET?

BTW: this is the classic producer/consumer problem.

An easy solution, which should perform very well too, is sketched below.

The AutoResetEvent below is entirely optional code, but usefull if you
have a dedicated thread for running ProcessList.

readonly IList Queue; // Use ArrayList or LinkedList or whatever
readonly AutoResetEvent QueueNotEmpty = new AutoResetEvent();
public void OnDriverSendResult(RackDetail detail) {
lock ( Queue ) {
Queue.Add(detail);
QueueNotEmpty.Set();
}
}

private static IList emptyList; // choose any empty list to init with
public void ProcessList() {
IList process;
QueueNotEmpty.WaitOne();
lock ( Queue ) {
if ( Queue.GetEnumerator().MoveNext() ) { // non-empty?
process = new ArrayList(l);
Queue.Clear();
} else {
process = emptyList;
}
foreach ( RackDetail detail in process )
Process(detail);
}
 
Back
Top