Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / New Users / February 2005

Tip: Looking for answers? Try searching our database.

Interlocked vs Mutex efficiency

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Chris Tanger - 18 Feb 2005 17:51 GMT
I have the following two code blocks which should only have 3 threads at the
most calling the function and collisions are very unlikely because all 3
threads should rarely be calling this function at the *exact* same time.  I
am wondering which code block I should use for optimum efficiency and speed
given the conditions.  I've hear that the Interlocked class is much more
efficient than a Mutex and should be used when it makes sense to, however I
don't know if this is true for sure.   I've heard that the Mutex will cause
(or is it *may* cause) a context switch and that the Interlocked class does
not.  Which code block will be fastest and why?

Thanks,

// **** Code block 1*****

bool sendMsgToIFac = false;

do
{
    int lastSeqNum = this.lastSeqNumReceived;
    int newSeqNum;

    if(
        (seqNum != (lastSeqNum + 1))
        && !(seqNum == 0 && (lastSeqNum == (this.maxSeqNums - 1)))
        )
    {
        // Ignore message, unexpected seq num

        newSeqNum = lastSeqNum;
        sendMsgToIFac = false;
    }
    else
    {
        newSeqNum = lastSeqNum + 1;
        if(newSeqNum > this.maxSeqNums - 1)
            newSeqNum = 0;
        sendMsgToIFac = true;
    }

} while(lastSeqNum != Interlocked.CompareExchange(ref lastSeqNumReceived,
newSeqNum, lastSeqNum));

//**** OR *******  Code block 2

bool sendMsgToIFac = false;
this.receiveSeqNumMutex.WaitOne();
if(
    (seqNum != (this.lastSeqNumReceived + 1))
    && !(seqNum == 0 && (this.lastSeqNumReceived == (this.maxSeqNums - 1)))
    )
{
    // Ignore message, unexpected seq num
    sendMsgToIFac = false;
}
else
{
    this.lastSeqNumReceived++;
    if(this.lastSeqNumReceived > this.maxSeqNums - 1)
        this.lastSeqNumReceived = 0;
    sendMsgToIFac = true;
}
this.receiveSeqNumMutex.ReleaseMutex();

Also, from the following article:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/c
pconThreadingDesignGuidelines.asp


"
Be aware of issues with the lock statement (SyncLock in Visual Basic). It is
tempting to use the lock statement to solve all threading problems. However,
the System.Threading.Interlocked Class is superior for updates that must be
atomic. It executes a single lock prefix if there is no contention. In a code
review, you should watch out for instances like the one shown in the
following example.
[Visual Basic]
SyncLock Me
  myField += 1
End SyncLock
[C#]
lock(this)
{
  myField++;
}
If you replace the previous example with the following one, you will improve
performance.

[Visual Basic]
System.Threading.Interlocked.Increment(myField)
[C#]
System.Threading.Interlocked.Increment(myField);
"

Why is the Interlocked version more efficient than the lock version?

Thanks,

Signature

- Chris Tanger

WXS - 18 Feb 2005 19:49 GMT
I do C#, so not aware of particular VB issues, but generally you would almost
always choose a Monitor/Lock over a mutext unless you need a named or cross
process mutext for some reason.  If all you need to do is increment a counter
that you won't be in contention too often I would think Interlocked methods
would be the way to go.  Also never do lock(this) as in that example code to
avoid potential deadlocks, instead allocate and internal object and lock on
that instead of lock(this).

Interlocked methods use a processor instruction to increment or exchange
values atomically.  They do this by locking the cache for that area of memory
for the duration of the instruction so that no other CPU could get it and
that instruction is atomic on the single CPU so will not be interrupted.  So
in theory depending on usage (not using it all over the place) it could be
very fast, but if you use it all over the place you are locking the cache
memory for that instruction length so another processor could not get it.  On
single processor since it executes atomically I would presume it is not as
big of an issue (since everything will be multicore soon though think
multiprocessor).

> I have the following two code blocks which should only have 3 threads at the
> most calling the function and collisions are very unlikely because all 3
[quoted text clipped - 90 lines]
>
> Thanks,
William Stacey [MVP] - 18 Feb 2005 21:29 GMT
If you only have one CPU, 3 threads can not access at same time *exactly
anyway as only one thread can run at one time.  If thread1 gets the lock and
OS switches to thread2 it could, however, block on the lock.  Just use
Lock() {} (i.e. Monitor).  Best overall in performance and ease of use and
getting it correct.  Using things like Interlocked.CompareExchange for sync
is hard to get right and probably not worth the effort.

Signature

William Stacey, MVP
http://mvp.support.microsoft.com

> I have the following two code blocks which should only have 3 threads at the
> most calling the function and collisions are very unlikely because all 3
[quoted text clipped - 60 lines]
>
> Also, from the following article:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/c
pconThreadingDesignGuidelines.asp


> "
> Be aware of issues with the lock statement (SyncLock in Visual Basic). It is
[quoted text clipped - 24 lines]
>
> Thanks,
WXS - 19 Feb 2005 02:27 GMT
I would mostly agree (Except there will be multicore processors soon).  
Definately for ease of use and getting it right the
lock(myinternalobjectlock) construct is much easier for the majority of
people to use and get right.  InterlockedCompareExchange is much tougher to
get right in that scenario.  If done right it can be faster, but if done
wrong it either isn't or utterly fails.

> If you only have one CPU, 3 threads can not access at same time *exactly
> anyway as only one thread can run at one time.  If thread1 gets the lock and
[quoted text clipped - 109 lines]
> >
> > Thanks,
Chris Tanger - 28 Feb 2005 10:47 GMT
   I think I can get the Interlocked right, it isn't that complicated.  For
the moment I will use lock though to keep things simple.  I AM interested in
performance and scalabilty as I am writing a server program that services
about 1000 clients and it does run on dual processor servers.

Thanks for the help.

-Chris

> I would mostly agree (Except there will be multicore processors soon).  
> Definately for ease of use and getting it right the
[quoted text clipped - 116 lines]
> > >
> > > Thanks,
David Browne - 18 Feb 2005 21:45 GMT
. . .
> [Visual Basic]
> SyncLock Me
[quoted text clipped - 16 lines]
>
> Why is the Interlocked version more efficient than the lock version?

This bit of advice fails utterly to understand the scale of the performance
difference between these two approaches, and risks using InterlockedXXX when
scope-based locking is more appropriate.  For most programmers it's not
worth keeping track of multiple synchronization objects and when to use each
one.  Just use lock/SyncLock all the time.

Interlocked.Increment is implemented in the processor, and is faster.  But
lock/SyncLock is a lightweight user-mode lock, so the performance difference
between them is usually insignificant.  Mutexes are kernel-based, and so are
slower.  So they should only be used when you need the extra functionality
of a Mutex (name, cross-process synchronization, abandoned waits).

The important thing to understand is the scope of the lock required to make
the code correct.  In your example, the two methods of syncronization were
not equivilent.  The mutex protected a whole block, the Interlocked method
only protected one statement.  This is the shortcoming of the Interlocked
methods: they only syncronize a single atomic operation on a variable.

The exaple posted should use lock, not a Mutex or an Interlocked Function.
A lock() scope will automatically unlock in case of an exception, and it
makes it very obvious what operations are being synchronized.

bool sendMsgToIFac = false;
lock(this)
{
if(
(seqNum != (this.lastSeqNumReceived + 1))
&& !(seqNum == 0 && (this.lastSeqNumReceived == (this.maxSeqNums - 1)))
)
{
// Ignore message, unexpected seq num
 sendMsgToIFac = false;
}
else
{
 this.lastSeqNumReceived++;
 if(this.lastSeqNumReceived > this.maxSeqNums - 1)
 this.lastSeqNumReceived = 0;
 sendMsgToIFac = true;
}
}

David
WXS - 20 Feb 2005 15:15 GMT
A quick test of 1 million iterations of lock(object) { increment++} vs
Interlocked.Increment gave a result on my machine 60ms for lock and 20ms for
Interlocked.  A 3 times improvement in performance.  As I and others have
stated more complex usages must be done with great care as exchanges are easy
to mess up and if there is too much contextion and used in too many places it
is possible to reduce efficiency

> I have the following two code blocks which should only have 3 threads at the
> most calling the function and collisions are very unlikely because all 3
[quoted text clipped - 90 lines]
>
> Thanks,

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.