Best Practice for a lock object across layers

S

sklett

I just finally found the cause of a bug I've been working on and it's a
threading issue. I have a shared resource (Image instance) that is being
manipulated in one thread and in another. I've been refreshing my multi
threading knowledge on Jon Skeet's fantastic articles (
http://www.yoda.arachsys.com/csharp/threads/ ). I need to ensure exclusive
access to this Image instance but I'm struggling with were to locate the
lock object. My application is based on the CAB framework which encourages
very lose coupling; As a result I don't have an easy way to share a lock
object between two subsystems. Or more accurately I should say I haven't
figured out a way to do it.

I'm curious how others have handled the issue of two threads in separate
classes or even assemblies that are accessing the same shared resource;
where do you place your lock objects?

Any suggestions greatly appreciated.


-SK
 
P

Peter Duniho

[...] I need to ensure exclusive
access to this Image instance but I'm struggling with were to locate the
lock object. My application is based on the CAB framework which
encourages
very lose coupling; As a result I don't have an easy way to share a lock
object between two subsystems. Or more accurately I should say I haven't
figured out a way to do it.

I'm curious how others have handled the issue of two threads in separate
classes or even assemblies that are accessing the same shared resource;
where do you place your lock objects?

It is not uncommon to use a named mutex (for example) for dealing with
synchronization across poorly-coupled components.

However, there's a good chance that the first options you should explore
have nothing to do with synchronization. In particular:

-- Don't share the instance at all. Make a copy when you need for the
data to be used by some other part of your system. Copy the results back
to your own instance if and when appropriate.

-- Serialize the use of the object. Specifically, if you hand the
instance of your object to the other part of your system, then don't touch
it again until that other part of your system has notified you (in
whatever way appropriate for the implementation) that it's done with the
object.

If you feel you must use some form of synchronization, you should consider
implementing it using the second option above. That is, have one code
path that actually does serialize access to the object, but have that code
path take the lock that protects the object while it's waiting for the
other system to be done with it. In that way, at least the lock can
remain on one side of the implementation, and the other system doesn't
have to worry about it at all.

For what it's worth, with respect to your specific question about "how
others have handled the issue of two threads in separate classes", in my
experience it's a very bad idea to try to do that. With proper
encapsulation, you should never have a single data structure that itself
doesn't implement thread-safety, and yet still needs for completely
independent classes to both cooperate on thread-safety.

It can be done, but IMHO you should try very hard to never need to.

Pete
 
S

sklett

Peter Duniho said:
However, there's a good chance that the first options you should explore
have nothing to do with synchronization. In particular:

-- Don't share the instance at all. Make a copy when you need for the
data to be used by some other part of your system. Copy the results back
to your own instance if and when appropriate.
As soon as I read this I liked it. It's much more appropriate for my
situation and requires less explanation. The feature causing the problems
was tossed in pretty quick so I didn't get to plan as much as I would have
liked; this solution is a great fit for the problem.

-- Serialize the use of the object. Specifically, if you hand the
instance of your object to the other part of your system, then don't touch
it again until that other part of your system has notified you (in
whatever way appropriate for the implementation) that it's done with the
object.

If you feel you must use some form of synchronization, you should consider
implementing it using the second option above. That is, have one code
path that actually does serialize access to the object, but have that code
path take the lock that protects the object while it's waiting for the
other system to be done with it. In that way, at least the lock can
remain on one side of the implementation, and the other system doesn't
have to worry about it at all.
Had you not suggested the simple copy solution (I don't know why I didn't
think of that) I would have gone with this solution. Also a good one.

Thank you for the response and suggestions. The solution is already
implemented (although I had to add support for IClonable all over the
place), tested and deployed. I can now go to sleep before work in 4 hours!
;0)

-SK
 

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

Top