best way for "atomic" like code parts execution?

  • Thread starter Thread starter SharpCoderMP
  • Start date Start date
S

SharpCoderMP

is it possible to implement some safe way of performing two or more
instructions in a kind of "atomic" way?

consider this: we have two queues (implemented on top of an List<T>).
now we need to move an element from one queue to another, so we need to
do something like this:
queue2.Enqueue(queue1.Dequeue());
int this case we may assume that nothing can cause this to fail
resulting in loss of the object we want to move.

great, but what if we've got the reference to some object on one queue
and we want it to move from one queue to another?
then we need something more or less like this:
Item item = queue1.GetItem(someItemIndex);
if (item.DoSomething())
{
queue2.Enqueue(item);
queue1.Remove(item);
}

now as you can see for a moment we have our item on two queues at the
same time. if we reverse the order of Enqueue and Remove, for the moment
our item wont be assigned to any of the queues.

in general this would not be a huge problem... but i deal with remoting
and quite a lot of asynchronous calls... so having the same item on two
queues at the same time or not having it on any of them at all may lead
to huge troubles. any ideas how these can be avoided?
 
Well, allowing for suitable compensator "catch" blocks, the only thing you
really neeed to watch out for is competing threads reading the queues while
you are mid-change.

However, if your competing threads are capable of doing this, you already
have major problems, as your code is inherently not thread safe.

The answer here is to lock (synchroize) /both/ containers prior to working
on them. All other threads (including remoting) should be doing likewise,
annd then there is no problem. Of course, you need to agree on the lock
order to avoid deadlocks...

Marc
 
thanks... um... lock... temporary stupidity got me ;P
lock should work fine.

but you suggest to lock containers - wouldn't it be better to only lock
the item we're currently dealing with?
 
No, as you don't want to add or remove any items for any queue outside of a
lock (if multiple threads).
So, if you can do it, try to use 1 lock for both queues as their syncLock.
Then if you need a multi-step operation, just take the lock and move stuff
around and exit lock.

private void MoveStuff()
{
lock(syncRoot)
{
// Move stuff around.
}
}

--
William Stacey [C# MVP]

| thanks... um... lock... temporary stupidity got me ;P
| lock should work fine.
|
| but you suggest to lock containers - wouldn't it be better to only lock
| the item we're currently dealing with?
 
Personally I'd try and see if I could use separate locks for the
containers, so that in normal operation they can be used independently,
and only take out both locks when transferring... of course, this makes
it more complex and (if not done correctly) prone to deadlock.

Of course, if this (separate access when not transferring) isn't an
issue, or you only have a few threads (so no need to support larger
parallelism) stick with one lock for simplicity.

Marc
 

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

Back
Top