|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Interlocked vs Mutex efficiencymost 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/cpconThreadingDesignGuidelines.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, -- - Chris Tanger 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). Show quoteHide quote "Chris Tanger" wrote: > > 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/cpconThreadingDesignGuidelines.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, > > -- > - Chris Tanger > 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. Show quoteHide quote "Chris Tanger" <chrisNnOoSsPpAaMmtan***@technocisive.com> wrote in message http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconThreadingDesignGuidelines.aspnews:684BD992-92A6-4D14-9F12-F350D3FF61E1@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 > 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: > Show quoteHide quote > > " > 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, > > -- > - Chris Tanger > 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. Show quoteHide quote "William Stacey [MVP]" wrote: > 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. > > -- > William Stacey, MVP > http://mvp.support.microsoft.com > > "Chris Tanger" <chrisNnOoSsPpAaMmtan***@technocisive.com> wrote in message > news:684BD992-92A6-4D14-9F12-F350D3FF61E1@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 > > 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/cpconThreadingDesignGuidelines.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, > > > > -- > > - Chris Tanger > > > > 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 Show quoteHide quote "WXS" wrote: > 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. > > "William Stacey [MVP]" wrote: > > > 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. > > > > -- > > William Stacey, MVP > > http://mvp.support.microsoft.com > > > > "Chris Tanger" <chrisNnOoSsPpAaMmtan***@technocisive.com> wrote in message > > news:684BD992-92A6-4D14-9F12-F350D3FF61E1@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 > > > 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/cpconThreadingDesignGuidelines.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, > > > > > > -- > > > - Chris Tanger > > > > > > > .. . .
Show quoteHide quote > [Visual Basic] This bit of advice fails utterly to understand the scale of the performance > 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? > 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 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 Show quoteHide quote "Chris Tanger" wrote: > > 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/cpconThreadingDesignGuidelines.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, > > -- > - Chris Tanger >
Other interesting topics
Finalization and .NET/deterministic or orderly shutdown
Using AL.exe to link modules into assembly How to negotiate authenication with HttpWebRequest Reversing text in TreeView nodes Reading Text datatype into a byte Array Strange behaviour with .NET apps with Framework 2.0 Deserialization constructor State of Objects... limits for filestreams (C#) Accessing information on IIS programatically |
|||||||||||||||||||||||