From: Michal on
Hi,

maybe it's a simple problem for most of you, but I can't find an easy way to
quite simple problem, let me describe:

Let's have this code:

public ClassToChange()
{
... //some other methods

internal List<AnyDataClass> LockAndGetData()
{
Monitor.Enter(cs);
return data;
}

internal Unlock()
{
Monitor.Exit(cs);
}

private object cs = new object();
private List<AnyDataClass> data = new List<AnyDataClass>();
}

public class Editor
{
public Editor(ClassToChange editedObject)
{
this.editedObject = editedObject;
}

public void MyFunctionToChangeData()
{
List<AnyDataClass> data = editedObject.LockAndGetData();

... // change data

editedObject.Unlock();
}

private ClassToChange editedObject;
}


class Program
{
static void Main()
{
Editor ed = new Editor(new ClassToChange());
ed.MyFunctionToChangeData();
}
}

So my aim is to let Editor change the data of ClassToChange in a thread-safe
way. But as you can see to call all the List data =
editedObject.LockAndGetData(), then not to forget the editedObject.Unlock()
is very boring to write (and not so safe). Do you have any easy solution for
this?

Only solution I have, there might be the CS as attribute of ClassToChange
and use lock {} in Editor, but I would need an attribute to every data object
of ClassToChange, who would check if the cs is locked to make it safe. So
that's also not a good way.

Any ideas?
From: Peter Duniho on
Michal wrote:
> [...]
> So my aim is to let Editor change the data of ClassToChange in a thread-safe
> way. But as you can see to call all the List data =
> editedObject.LockAndGetData(), then not to forget the editedObject.Unlock()
> is very boring to write (and not so safe). Do you have any easy solution for
> this?
>
> Only solution I have, there might be the CS as attribute of ClassToChange
> and use lock {} in Editor, but I would need an attribute to every data object
> of ClassToChange, who would check if the cs is locked to make it safe. So
> that's also not a good way.
>
> Any ideas?

If the synchronization needs to happen at the level of operations within
the Editor class, then your synchronization object should also be in the
Editor class.

Of course, this means that the Editor class has to be the de facto owner
of your ClassToChange instance, and no other code should be modifying
the ClassToChange instance while the Editor class is manipulating it.
But that's just good program design anyway. It should not be a problem
to require that.

In some cases, it may be feasible to simply make the ClassToChange class
the thread-safe one. In that case, rather than having the Editor class
try to lock and unlock, just do the synchronization in the ClassToChange
class for each operation that might modify the class's contents. This
would lead to more locking and unlocking, but coherency of the data
would still be preserved.

Finally, if you decide that neither of the above can possibly work (and
I would recommend strongly that you not come to that conclusion…in
particular, in your example it really looks like the synchronization
should be handled entirely by the Editor class, with the ClassToChange
class being left not thread safe), you could implement a "do work"
interface in your ClassToChange class, so that the Editor class simply
passes a delegate that is invoked while the lock is held. For example:

class ClassToChange
{
void DoSynchronizedWork(Action action)
{
lock (cs)
{
action();
}
}

private readonly object cs = new object();
}

class Editor
{
public void MyFunctionToChangeData()
{
editedObject.DoSynchronizedWork(MyFunctionToChangeDataImpl);
}

private void MyFunctionToChangeDataImpl()
{
// change data
}

private ClassToChange editedObject;
}

Hope that helps.

Pete
From: Patrice on
Hello,

> So my aim is to let Editor change the data of ClassToChange in a
> thread-safe
> way. But as you can see to call all the List data =
> editedObject.LockAndGetData(), then not to forget the
> editedObject.Unlock()
> is very boring to write (and not so safe). Do you have any easy solution
> for
> this?

Try the SyncLock statement that is intended to simplify Enter/Exit calls.
The doc is at :

http://msdn.microsoft.com/en-us/library/3a86s51t(VS.80).aspx

--
Patrice



From: Peter Duniho on
Patrice wrote:
> Try the SyncLock statement that is intended to simplify Enter/Exit calls.
> The doc is at :
>
> http://msdn.microsoft.com/en-us/library/3a86s51t(VS.80).aspx

This is the C# newsgroup. The equivalent is the "lock" statement.
Neither VB.NET's "SyncLock" nor C#'s "lock" offer the semantics that the
OP is asking for (i.e. retaining the lock across method calls).

Granted, as I suggested in my reply to the OP, the semantics being asked
for should be avoided. :) Nevertheless, I don't think that suggesting
"lock" (or "SyncLock", were this a VB.NET newsgroup) would in and of
itself suffice to answer the question.

Pete
From: Patrice on
> This is the C# newsgroup. The equivalent is the "lock" statement. Neither
> VB.NET's "SyncLock" nor C#'s "lock" offer the semantics that the OP is
> asking for (i.e. retaining the lock across method calls).

Good point. Sometimes I just mix groups.

IMO retaining the lock was not the OP intent and was more caused by the
implementation attempt...

--
Patrice