473,387 Members | 1,573 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

To lock or not?

I have a class as follows:

public class OperationFeedback
{
DateTime _startTime;

public DateTime StartTime
{
get
{
return _startTime;
}
set
{
_startTime = value;
}
}

}

Set will occur in a background thread. Getting will occur from my GUI
thread. Should I implement a lock inside the get and set? If I so why?

Thanks,

- Fritz
Jan 15 '08 #1
11 7946
Fritz,

If the StartTime property is the only one item that you need to
synchronize, then I would say in the class is fine. However, as a general
guideline, I think that there are few classes that should do this (even this
one). The reason for this is that operations are usually more complex than
simple get/sets, and you really should be wrapping those entire operations
in lock blocks to make sure that the whole operation is synchronized, not
just one part of it.

Of course, if you encapsulate your operations well enough, you can
synchronize access to those in a class.

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

<fr********@gmail.comwrote in message
news:13**********************************@i12g2000 prf.googlegroups.com...
>I have a class as follows:

public class OperationFeedback
{
DateTime _startTime;

public DateTime StartTime
{
get
{
return _startTime;
}
set
{
_startTime = value;
}
}

}

Set will occur in a background thread. Getting will occur from my GUI
thread. Should I implement a lock inside the get and set? If I so why?

Thanks,

- Fritz

Jan 15 '08 #2
If I leave the class as is? Is it possible that when the "get" is
called from one thread in the middle of the "set" from another, that
the value could contain part of the old and part of the new value
(since DateTime is not atomic). If I want to ensure a proper value
when I "get", I suspect I need to lock (this is what I am trying to
confirm / understand).

- Fritz
Jan 15 '08 #3
the value could contain part of the old and part of the new value

So are you saying that you are worried about having a stored value of say
"3/3/2003 3:33 PM" and then having the set method called to set a new value
of say "5/5/2005 5:55 AM" and during this process call the get method and
end up reading something like "5/5/2005 3:33 PM" (contain part of the old
and part of the new value)?

Did I totally misunderstand your question? :)
Jan 15 '08 #4
On Jan 15, 3:44 pm, "Rene" <a...@b.comwrote:
the value could contain part of the old and part of the new value

So are you saying that you are worried about having a stored value of say
"3/3/2003 3:33 PM" and then having the set method called to set a new value
of say "5/5/2005 5:55 AM" and during this process call the get method and
end up reading something like "5/5/2005 3:33 PM" (contain part of the old
and part of the new value)?

Did I totally misunderstand your question? :)
No, that is my concern. Although I'm not sure it would manifest itself
exactly like that (this would depend on the internal implementation
DateTime).

- Fritz
Jan 15 '08 #5
On 15 Jan, 22:16, Fritz <fritzcw...@gmail.comwrote:
On Jan 15, 3:44 pm, "Rene" <a...@b.comwrote:
the value could contain part of the old and part of the new value
So are you saying that you are worried about having a stored value of say
"3/3/2003 3:33 PM" and then having the set method called to set a new value
of say "5/5/2005 5:55 AM" and during this process call the get method and
end up reading something like "5/5/2005 3:33 PM" (contain part of the old
and part of the new value)?
Did I totally misunderstand your question? :)

No, that is my concern. Although I'm not sure it would manifest itself
exactly like that (this would depend on the internal implementation
DateTime).

- Fritz
DateTime is a 64 bit structure. If you look at the MSDN entry there is
an explicit warning that it is not thread safe on certain
architectures as threads could switch before it is completely commited.
Jan 16 '08 #6

"Fritz" <fr********@gmail.comwrote in message
news:dc**********************************@y5g2000h sf.googlegroups.com...
On Jan 15, 3:44 pm, "Rene" <a...@b.comwrote:
the value could contain part of the old and part of the new value

So are you saying that you are worried about having a stored value of say
"3/3/2003 3:33 PM" and then having the set method called to set a new
value
of say "5/5/2005 5:55 AM" and during this process call the get method and
end up reading something like "5/5/2005 3:33 PM" (contain part of the old
and part of the new value)?

Did I totally misunderstand your question? :)

No, that is my concern. Although I'm not sure it would manifest itself
exactly like that (this would depend on the internal implementation
DateTime).

- Fritz
Yes, it looks like that could potentially happen (on 32-bit Windows). The
DateTime type stores its value internally as a UInt64. According to
http://msdn2.microsoft.com/en-us/library/ms684122.aspx, read and writes of
64 bit values are not guaranteed to be atomic on 32-bit Windows, so
potentially the writing thread might only get time to write half of the
bytes before it gets interupted by the reading thread.

I have no idea how common this problem is or if it even exists in practice.
The article only make a general statement regarding 32-bit Windows. The
behavoiur might very well be that it's an atomic operation on XP and Vista,
but not on 2000 for example (note: I'm only guessing here).

For the record, I've never seen it happen (fwiw :-)).

/claes


Jan 16 '08 #7
Doing it on that granular a level actually increases your chances of
deadlock, assuming you are mixing it with other methods/properties that
lock on that granular a level.
Why is that though? I would have locking get/set of each property would be
better as long as the property is doing nothing but returning some state.

Also, in this case I would guess a reader/writer lock would work fine as
well.

---
Ajay

Jan 18 '08 #8
On Thu, 17 Jan 2008 19:31:19 -0800, Ajay Kalra <aj*******@yahoo.comwrote:
> Doing it on that granular a level actually increases your chances of
deadlock, assuming you are mixing it with other methods/properties that
lock on that granular a level.

Why is that though? I would have locking get/set of each property would
be better as long as the property is doing nothing but returning some
state.
Consider first that deadlocking code is buggy code. So the real question
is, why would locking at a finer level of granularity lead to more bugs?

The answer is simply that of opportunity. If you have only one lock,
there's no chance for deadlock at all. If you have two locks, there's
some chance for deadlock but it's not too hard to design around that
possibility. If you have fifty locks, then you've got some huge number of
permutations that could lead to deadlock. Make a single mistake and BOOM!

Pete
Jan 18 '08 #9

"Peter Duniho" <Np*********@nnowslpianmk.comwrote in message
news:op***************@petes-computer.local...
On Thu, 17 Jan 2008 19:31:19 -0800, Ajay Kalra <aj*******@yahoo.com>
wrote:
>> Doing it on that granular a level actually increases your chances of
deadlock, assuming you are mixing it with other methods/properties that
lock on that granular a level.

Why is that though? I would have locking get/set of each property would
be better as long as the property is doing nothing but returning some
state.

Consider first that deadlocking code is buggy code. So the real question
is, why would locking at a finer level of granularity lead to more bugs?

The answer is simply that of opportunity. If you have only one lock,
there's no chance for deadlock at all. If you have two locks, there's
some chance for deadlock but it's not too hard to design around that
possibility. If you have fifty locks, then you've got some huge number of
permutations that could lead to deadlock. Make a single mistake and BOOM!

I didnt say that we have multiple lock objects. You can use the same object.
In this case, all getter can acquire a readonlylock. For setters, I would
use the same object on which you apply the lock. Why is that hmm... bad?

I am curious to know because we follow this pattern and have had no issues
at all. I would like to know the downside that we are missing.
---
Ajay

Jan 18 '08 #10
On Thu, 17 Jan 2008 20:23:13 -0800, Ajay Kalra <aj*******@yahoo.comwrote:
I didnt say that we have multiple lock objects. You can use the same
object. In this case, all getter can acquire a readonlylock. For
setters, I would use the same object on which you apply the lock. Why is
that hmm... bad?
Well, not having multiple lock objects but then locking at such a low
level is also bad, but for performance reasons.

It really just depends. Without knowing everything that's going on with
the code, it's hard to say. Sometimes a fine-granularity on your locking
code is no problem. But as Nicholas says, often times you've got a
situation where at that level of granularity you're just going to keep
acquiring the same lock over and over. You're better off in that
situation to just grab the lock once, do everything you need to do, and
then release it.
I am curious to know because we follow this pattern and have had no
issues at all. I would like to know the downside that we are missing.
If you understand the _potential_ for problems and can ensure they are not
an issue here, you should be okay. If all you are ever locking is that
one DateTime property, it's not an issue.

That said, if all you're ever locking is that one DateTime property then
you may not need the lock at all. You can use boxing instead to create an
atomic access:

object _startTime = new DateTime();

public DateTime StartTime
{
get { return (DateTime)_startTime; }
set { _startTime = value; }
}

I did a quick test (code below) and two threads executing 10 million
iterations accessing both the setter and getter of the property are
consistently 30-40% faster using boxing than using a lock. Of course,
even the "slow" case took only 1.1 seconds to do 10 million iterations.
The usual caveat of "most code is going to spend most of its time doing
more interesting things" applies, meaning that even if you could get the
overhead down to zero it might not make a real difference in your
application's performance.

On the other hand, if you are entering and leaving a lock for every little
thing, that might cause that caveat to no longer be applicable. All of
the sudden, performance matters. :)

Pete

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace TestLockPerformance
{
class Program
{
public interface IDateTimeHolder
{
DateTime DateTime
{
get;
set;
}
}

public class LockingHolder : IDateTimeHolder
{
#region IDateTimeHolder Members

private DateTime _dt;
private object _objLock = new object();

public DateTime DateTime
{
get
{
lock (_objLock)
{
return _dt;
}
}
set
{
lock (_objLock)
{
_dt = value;
}
}
}

#endregion
}

public class BoxingHolder : IDateTimeHolder
{
#region IDateTimeHolder Members

private volatile object _dt = new DateTime();

public DateTime DateTime
{
get
{
return (DateTime)_dt;
}
set
{
_dt = value;
}
}

#endregion
}

public class HolderThread
{
private IDateTimeHolder _dth;
private int _iterations;
private Thread _thread;

public HolderThread(IDateTimeHolder dth, int iterations)
{
_dth = dth;
_iterations = iterations;
_thread = new Thread(_ThreadStart);
}

public void Start()
{
_thread.Start();
}

public void Wait()
{
_thread.Join();
}

private void _ThreadStart()
{
while (_iterations-- 0)
{
DateTime dtT = _dth.DateTime;

_dth.DateTime = dtT;
}
}
}

static void Main(string[] args)
{
int iterations = 10000000;

switch (args.Length)
{
case 2:
{
int iT;

if (int.TryParse(args[1], out iT))
{
iterations = iT;
}
}
goto case 1;
case 1:
{
IDateTimeHolder dth;

switch (args[0])
{
case "lock":
dth = new LockingHolder();
break;
case "box":
dth = new BoxingHolder();
break;
default:
Console.WriteLine("first parameter mustbe
\"lock\" or \"box\"");
dth = null;
break;
}

if (dth != null)
{
HolderThread ht1 = new HolderThread(dth,
iterations),
ht2 = new HolderThread(dth, iterations);

Stopwatch sw = new Stopwatch();
sw.Start();
ht1.Start();
ht2.Start();
ht1.Wait();
ht2.Wait();
sw.Stop();

Console.WriteLine("{0} iterations took {1}",
iterations, sw.Elapsed);
}
}
break;
default:
Console.WriteLine("usage: {0} lock|box [<iteration
count>]", Environment.CommandLine.Split(' ')[0]);
break;
}
}
}
}
Jan 18 '08 #11
Thanks Pete. It was helpful. I didnt know about Boxing making it atomic.

---
Ajay

"Peter Duniho" <Np*********@nnowslpianmk.comwrote in message
news:op***************@petes-computer.local...
On Thu, 17 Jan 2008 20:23:13 -0800, Ajay Kalra <aj*******@yahoo.comwrote:
I didnt say that we have multiple lock objects. You can use the same
object. In this case, all getter can acquire a readonlylock. For setters,
I would use the same object on which you apply the lock. Why is that
hmm... bad?
Well, not having multiple lock objects but then locking at such a low
level is also bad, but for performance reasons.

It really just depends. Without knowing everything that's going on with
the code, it's hard to say. Sometimes a fine-granularity on your locking
code is no problem. But as Nicholas says, often times you've got a
situation where at that level of granularity you're just going to keep
acquiring the same lock over and over. You're better off in that
situation to just grab the lock once, do everything you need to do, and
then release it.
I am curious to know because we follow this pattern and have had no
issues at all. I would like to know the downside that we are missing.
If you understand the _potential_ for problems and can ensure they are not
an issue here, you should be okay. If all you are ever locking is that
one DateTime property, it's not an issue.

That said, if all you're ever locking is that one DateTime property then
you may not need the lock at all. You can use boxing instead to create an
atomic access:

object _startTime = new DateTime();

public DateTime StartTime
{
get { return (DateTime)_startTime; }
set { _startTime = value; }
}

I did a quick test (code below) and two threads executing 10 million
iterations accessing both the setter and getter of the property are
consistently 30-40% faster using boxing than using a lock. Of course,
even the "slow" case took only 1.1 seconds to do 10 million iterations.
The usual caveat of "most code is going to spend most of its time doing
more interesting things" applies, meaning that even if you could get the
overhead down to zero it might not make a real difference in your
application's performance.

On the other hand, if you are entering and leaving a lock for every little
thing, that might cause that caveat to no longer be applicable. All of
the sudden, performance matters. :)

Pete

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace TestLockPerformance
{
class Program
{
public interface IDateTimeHolder
{
DateTime DateTime
{
get;
set;
}
}

public class LockingHolder : IDateTimeHolder
{
#region IDateTimeHolder Members

private DateTime _dt;
private object _objLock = new object();

public DateTime DateTime
{
get
{
lock (_objLock)
{
return _dt;
}
}
set
{
lock (_objLock)
{
_dt = value;
}
}
}

#endregion
}

public class BoxingHolder : IDateTimeHolder
{
#region IDateTimeHolder Members

private volatile object _dt = new DateTime();

public DateTime DateTime
{
get
{
return (DateTime)_dt;
}
set
{
_dt = value;
}
}

#endregion
}

public class HolderThread
{
private IDateTimeHolder _dth;
private int _iterations;
private Thread _thread;

public HolderThread(IDateTimeHolder dth, int iterations)
{
_dth = dth;
_iterations = iterations;
_thread = new Thread(_ThreadStart);
}

public void Start()
{
_thread.Start();
}

public void Wait()
{
_thread.Join();
}

private void _ThreadStart()
{
while (_iterations-- 0)
{
DateTime dtT = _dth.DateTime;

_dth.DateTime = dtT;
}
}
}

static void Main(string[] args)
{
int iterations = 10000000;

switch (args.Length)
{
case 2:
{
int iT;

if (int.TryParse(args[1], out iT))
{
iterations = iT;
}
}
goto case 1;
case 1:
{
IDateTimeHolder dth;

switch (args[0])
{
case "lock":
dth = new LockingHolder();
break;
case "box":
dth = new BoxingHolder();
break;
default:
Console.WriteLine("first parameter must be
\"lock\" or \"box\"");
dth = null;
break;
}

if (dth != null)
{
HolderThread ht1 = new HolderThread(dth,
iterations),
ht2 = new HolderThread(dth, iterations);

Stopwatch sw = new Stopwatch();
sw.Start();
ht1.Start();
ht2.Start();
ht1.Wait();
ht2.Wait();
sw.Stop();

Console.WriteLine("{0} iterations took {1}",
iterations, sw.Elapsed);
}
}
break;
default:
Console.WriteLine("usage: {0} lock|box [<iteration
count>]", Environment.CommandLine.Split(' ')[0]);
break;
}
}
}
}

Jan 19 '08 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: xixi | last post by:
can someone explain to me what is internal p lock, internal s lock, internal v lock? when i have IS lock or IX lock , i always have these internal locks together for the application handle ...
0
by: Bruce Pullen | last post by:
DB2 v7.2 (FP7 - DB2 v7.1.0.68) on AIX 5.2.0.0. We're seeing unexpected single row (then commit) insert locking behaviour. We're seeing Applications that already hold row-level W locks in...
7
by: Sunny | last post by:
Hi, I can not understend completely the lock statement. Actally what is locked: 1. the part of the code between {...} or 2. the object in lock() In the docs is written: for 1: The lock...
3
by: Invalid | last post by:
I launch a worker thread that periodically reads a volatile bool abortRequested, which could be set to true by my main form. IOW, there is one thread that can read that bool and one different...
0
by: Nashat Wanly | last post by:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaskdr/html/askgui06032003.asp Don't Lock Type Objects! Why Lock(typeof(ClassName)) or SyncLock GetType(ClassName) Is Bad Rico...
1
by: charlies224 | last post by:
Hi, I am writting a software that requires me to make sure the Num Lock is always on and Caps Lock is always off. First, I know how to detect if Num Lock or Caps Lock is on or off (if...
3
by: Raj | last post by:
I created a refresh deferred MQT, and during full refresh there were 4 or 5 lock waits, all waiting on a 'S' lock on Internal Catalog Cache ? Can some one explain how to prevent this from happening?
2
by: shenanwei | last post by:
DB2 V8.2 on AIX, type II index is created. I see this from deadlock event monitor. 5) Deadlocked Connection ... Participant no.: 2 Lock wait start time: 09/18/2006 23:04:09.911774 .........
190
by: blangela | last post by:
If you had asked me 5 years ago about the future of C++, I would have told you that its future was assured for many years to come. Recently, I have been starting to wonder. I have been teaching...
94
by: Samuel R. Neff | last post by:
When is it appropriate to use "volatile" keyword? The docs simply state: " The volatile modifier is usually used for a field that is accessed by multiple threads without using the lock...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.