using lock

  • Thread starter Thread starter marvind
  • Start date Start date
M

marvind

Hello,

Why doesn't the lock in Class2::Execute protect the critical section:

public Class1
{
...
public DataTable SchemaTable = new DataTable();
}

Class1 creates many instances of Class2 and calls the corresponding
Execute function on different threads.

public Class2
{
...
public void Execute()
{

// sync multiple threads - ensure only one thread obtains the
schema table
// does not really work, many threads enter this section at the
same time.
lock (_parent.SchemaTable)
{
if (0 == _parent.SchemaTable.Count)
{
_parent.SchemaTable = rdr.GetSchemaTable(); // returns a new
DataTable
}
}
...
}
...
}

I think the problem is that rdr.GetSchemaTable returns a new DataTable
that _parent.SchemaTable points at but I am not really clear how the
..NET internals work. I am able to get around this problem by using a
dedicated SyncLock object.

I would appreciate if someone could point out clearly why the code
should not be expected to work.

Thanks
 
marfind,

Yeah, this is definitely not good. A lock statement basically compiles
to the following:

// If you use lock (this) ;
Montior.Enter(this);

try
{
}
finally
{
Monitor.Exit(this);
}

So, by changing the contents of the reference that was passed to enter,
you never actually release the lock. In effect, you are allocating all of
these locks, which are never released, but every time you make a call, you
change the value of what is locked on the next call. That's why it never
works.

I'm surprized the compiler didn't catch this (it could be because you
are locking on something that is returned from the object).

In the end, you are on the right track, using a dedicated sync lock
object for the lock.

Hope this helps.
 
Nicholas Paldino said:
Yeah, this is definitely not good. A lock statement basically compiles
to the following:

// If you use lock (this) ;
Montior.Enter(this);

try
{
}
finally
{
Monitor.Exit(this);
}

So, by changing the contents of the reference that was passed to enter,
you never actually release the lock.

No, that's not true.

According to the spec:

<quote>
A lock statement of the form

lock (x) ...

where x is an expression of a reference-type, is precisely equivalent
to

System.Threading.Monitor.Enter(x);
try {
...
}
finally {
System.Threading.Monitor.Exit(x);
}

except that x is only evaluated once.
</quote>

Note the "x is only evaluated once" bit.

The lock is correctly released, but it won't be the same lock that is
acquired by the next call.
 
Back
Top