Why Interlocked.CompareExchange is not working? - c#

if (Interlocked.CompareExchange(ref this.popcount, this.popcount + 1, this.popcount) == this.popcount)
{
pop = Interlocked.CompareExchange(ref head, head.next, head);
}
I write a code but somehow it's not working as I wanted...
Interlocked.CompareExchange(ref this.popcount, this.popcount + 1, this.popcount)
I think this means
go to this.popcount reference and get value of popcount
compare value with this.popcount
if it is same, add 1 to this.popcount
Am I wrong? If I'm wrong, how can I correct it?

You need to remember the value that you added 1 to, the "before" value, and cannot rely on (re-) reading it from the variable you're going to change. Because the whole point is that multiple threads are competing to update this variable's value. So you want something like:
var oldcount = this.popcount;
var newcount = oldcount + 1;
if(Interlocked.CompareExchange(ref this.popcount, newcount, oldcount) == oldcount)
{
//It worked
}
else
{
//Loop round, try again, whatever you plan to do when you don't succeed.
}
With your example, even if the CompareExchange succeeds, you're then comparing the old value (returned by CompareExchange) to the new value (that you freshly read via this.popcount to the right of ==) and it's unlikely those will ever match. Conversely, they might be equal if your call to CompareExchange actually failed.
Of course, if you're just incrementing a variable, Interlocked.Increment would be more appropriate.

Related

Why is a lock required here?

I'm looking at an example on p. 40 of Stephen Cleary's book that is
// Note: this is not the most efficient implementation.
// This is just an example of using a lock to protect shared state.
static int ParallelSum(IEnumerable<int> values)
{
object mutex = new object();
int result = 0;
Parallel.ForEach(source: values,
localInit: () => 0,
body: (item, state, localValue) => localValue + item,
localFinally: localValue =>
{
lock (mutex)
result += localValue;
});
return result;
}
and I'm a little confused why the lock is needed. Because if all we're doing is summing a collection of ints, say {1, 5, 6}, then we shouldn't need to care about the shared sum result being incremented in any order.
(1 + 5) + 6 = 1 + (5 + 6) = (1 + 6) + 5 = ...
Can someone explain where my thinking here is flawed?
I guess I'm a little confused by the body of the method can't simply be
int result = 0;
Parallel.ForReach(values, (val) => { result += val; });
return result;
Operations such as addition are not atomic and thus are not thread safe. In the example code, if the lock was omitted, it's completely possible that two addition operations are executed near-simultaneously, resulting in one of the values being overridden or incorrectly added. There is a method that is thread safe to increment integers: Interlocked.Add(int, int). However, since this isn't being used, the lock is required in the example code to ensure that exactly one non-atomic addition operation at most is completed at a time (in sequence and not in parallel).
Its not about the order in which 'result' is updated, its the race condition of updating it, remember that operator += is not atomic, so two threads may not see the udpate of another's thread before they touch it
The statement result += localValue; is really saying result = result + localValue; You are both reading and updating a resource(variable) shared by different threads. This could easily lead into a Race Condition. lockmakes sure this statement at any given moment in time is accessed by a single thread.

Unassigned variable in return statement

for some reason I don't seem to be able to put the return in a fashion that captures this stored procedure's return value (0 or -1), either it returns the value which was used to initialize the variable or keeps telling me the local variable is unassigned.
public int changePass(int idUsuario, String old_pass, String new_pass)
{
int result;
try
{
DataTable tablaResultado =
DataBaseAccess.advanceStoredProcedureRequest(
"pa_usuario_change_pass",
new SPP[]
{
new SPP("id_usuario", idUsuario.ToString()),
new SPP("old_pass", old_pass.ToString()),
new SPP("new_pass", new_pass.ToString())
});
if (tablaResultado.Rows.Count > 0)
{
if (tablaResultado.Rows[0] != null)
{
result = (int.Parse(tablaResultado.Rows[0].ItemArray[0].ToString()));
}
}
return result;
}
catch (System.Data.SqlClient.SqlException sqlException)
{
throw sqlException;
}
}
I have multiple methods which follow the same pattern and all of those works, I have been trying to get this to work for awhile now, and I'm sure I'm overlooking something very, very obvious. Either way I cannot find it right now so I was hoping someone could refresh my memory or give me a tip.
The code only assigns a value to the result variable if two different conditions both happen to be true. That is, if the row count is > 0 and the first row is non-null. The compiler is telling you, completely legitimately, that your code contains a path to the return statement where the variable being used hasn't been assigned a value yet.
You need to decide what the method should return if either of those conditions are not true, and then assign that value to the result variable as part of its initialization.
EDIT:
To be clear: it seems you may be overlooking the possibility that your code won't successfully execute the stored procedure. But it can only return a value to be assigned to result when those two conditions are true. You either need to pick a default value that is reasonable to return when one or the other of the conditions aren't true, or you need to fix the code so that those conditions are always both true (and so the SP always executes successfully).

Totally unexplainable NullReferenceException

Ok, so I very sporadically get a NullReferenceException on this line of code:
if (!_oracleTenantSettings.OraclePlanSettings.ContainsKey(_key) || _oracleTenantSettings.OraclePlanSettings[_key] == null)
and/or this line:
_oraclePlanSettings = _oracleTenantSettings.OraclePlanSettings[_key];
where OraclePlanSettings is a SortedList, and it can't be null, because the code in question is surrounded by:
if (_oracleTenantSettings.OraclePlanSettings != null && _oracleTenantSettings.OraclePlanSettings.Count > 0)
So I'm getting a NRE, but there is not a single part of the entire line of code that could ever possibly be null, ever. Period. (sense the frustration?) And that includes the key, but that wouldn't throw a NRE anyway. I do not understand. Is it possible that VS is just misplacing the CLR exception? If so, where would be a good place to start looking?
The stack trace is just a one-liner:
at company.product.Mvc.OracleSettingsStoreCache.VerifyValueInCacheOrInsert[T](T& returnVal, SettingsType settingType, String tenantId, String planId, String pageMnemonic, String processId, String transcationType, String language, String country, String wapTransactionType, String wapCodeGroup, String wapLoanReasons, String palleteType, Boolean isInsert, Object _cacheValue) in blahblahblah.OracleSettingsStoreCache.cs:line 290
Here is the entire block of code:
if (!string.IsNullOrEmpty(tenantId) && (!IsWacMode() || (IsWacMode() && settingType == OracleSettingsType.SettingsType.FetchWAPInvestmentTransfer)) && _useCache != "false")
{
tenantId = tenantId.ToUpper().Trim();
_oracleTenantSettings = null;
if (_oracleCacheManager.Contains(_cacheKey))
_oracleTenantSettings = _oracleCacheManager.Get<OracleTenantSetting>(_cacheKey);
if (_oracleTenantSettings != null)
{
if (_oracleTenantSettings.OraclePlanSettings != null && _oracleTenantSettings.OraclePlanSettings.Count > 0)
{
_key = language + "_" + country + "_" + tenantId;
***LINE 290*** if (!_oracleTenantSettings.OraclePlanSettings.ContainsKey(_key) || _oracleTenantSettings.OraclePlanSettings[_key] == null)
{
_objectMissing = TypeOfObjectMissing.TenantObjectDoesNotExist;
}
}
Without seeing the context that code lives within, it's hard to be sure. But based on the symptoms you describe, i.e. very sporadic...inexplicable...something's null that can't be... I would strongly suspect a threading issue. For example, if the collection is static and potentially accessed by multiple threads, it can happen (although it's a rare occurrence of chance timing) that a second thread modifies the collection contents between when the first thread tests if something is there and when it accesses that something.
If that's the case, you must make your code more threadsafe. You can use lock or concurrent collections to avoid this problem. To use lock, you need to use a synchronization object (not a new object created on the fly). You would also want to hunt up ALL places where that collection is accessed, and surround every one with a lock...code that just looks at the collection must use lock as well as code that modifies the collection. This is a big topic for a SO answer, so I would recommend you use this really great resource:
http://www.albahari.com/threading/
Here is how you could get NREs in this case:
thread 1 checks if entry exists in SortedList myList for _key="hello"
gets true
thread 1 checks if entry for _key="hello" is non-null
gets true
thread 2 sets myList["hello"] = null
thread 1 executes myList["hello"].Something() and gets NRE.
Based on the edits to your post, it seems that in these lines
if (_oracleTenantSettings != null) {
if (_oracleTenantSettings.OraclePlanSettings != null && _oracleTenantSettings.OraclePlanSettings.Count > 0) {
_key = language + "_" + country + "_" + tenantId;
if (!_oracleTenantSettings.OraclePlanSettings.ContainsKey(_key) || _oracleTenantSettings.OraclePlanSettings[_key] == null)
if the NRE occurs on the last line, then right after executing the first line or second line, another thread can either set _oracleTenantSettings or _oracleTenantSettings.OraclePlanSettings to null. Either of those things happening would cause the final line to throw an NRE.
The following code is not the proper way to make your code thread safe, but might serve as a quick way to see if this is indeed the case since it would make this situation (the null reference exception) less likely:
var oracleTS = _oracleTenantSettings;
if (oracleTS != null) {
var planSettings = oracleTS.OraclePlanSettings;
if ((planSettings != null) && (planSettings.Count > 0)) {
_key = language + "_" + country + "_" + tenantId;
if (!planSettings.ContainsKey(_key) || planSettings[_key] == null)
Note that the final line could still have other issues related to threading like the key being removed by another thread between the first part of the conditional and the second part, or planSettings Count changing after being tested. But if this code drastically reduces the NREs, then you have a pretty good clue what was happening, and that you should go through and properly make your code thread safe with locks where needed. To say further, a person would need to know more about what other code is doing, especially code that modifies _oracleTenantSettings.
My guess is that there is another thread accessing the property.
A quick way to fix it would be locking on it every time you access it like this:
var oraclePlanSettings = _oracleTenantSettings.OraclePlanSettings;
lock (oraclePlanSettings)
{
// from now on you can safely access your cached reference "oraclePlanSettings"
if (oraclePlanSettings != null && oraclePlanSettings.Count > 0)
_oraclePlanSettings = oraclePlanSettings[_key]; // ... blabla
}
Beware of deadlocks tho.
I agree with the previous answers, It's probably a threading issue, but I have someting to add.
Here is a quick and dirty test to determine if it's threading or not.
Set up a scenerio that reproduces the error (say running it in several (10) threads in a constant loop overnight)
Apply this attribute to your class
[Synchronization]
Your Class must inherit from ContextBoundObject.
That forces all the instances of the class to run on a single thread (way slower).
Re run your test.
If your problem goes away, you have a threading issue. If speed is a concern, you need to go back and do all the locking around the code that touches that object. If you convert everything to use properties for the objects in question you can just lock the getter and setter.
If the quick and dirty test fails to fix the issue, it's probabaly something else. For instance if you're using unsafe code or unsafe dlls (ie stuff written in non .Net c++), it might be a memory corruption problem.
Hope this helps.
Here is more detail on the attribute, including inheriting from ContextBoundObject.
Ms Docs
Code sample:
// Context-bound type with the Synchronization context attribute.
[Synchronization()]
public class SampleSynchronized : ContextBoundObject {
// A method that does some work, and returns the square of the given number.
public int Square(int i) {
Console.Write("The hash of the thread executing ");
Console.WriteLine("SampleSynchronized.Square is: {0}",
Thread.CurrentThread.GetHashCode());
return i*i;
}
}
Update
I am proposing that somewhere in the code the Equality operator or the == has been overloaded on one of the related objects and the failure occurs when either null is not be checked for properly (or fails) or something is returned as equal when it is not.
Check for all operator overloads on == for any class object being used in this situation and rectify..
Original
Change the logic to this, for you want to first check for no key...THEN..do the check when there is a valid key but (and) its value is null:
if ((_oracleTenantSettings.OraclePlanSettings.ContainsKey(_key) == false) ||
((_oracleTenantSettings.OraclePlanSettings.ContainsKey(_key)) &&
_oracleTenantSettings.OraclePlanSettings[_key] == null)))
Its actually expected if you think through the logic flow of the original statements why it intermittently fails. :-)
EDIT:
Let me explain, Follow this logic by steps
In the original if clause when it evaluates the (!ContainsKey(_key)) means that when the key is NOT there (true) it gets changed to FALSE.
Then the Or kicks in because of False in #1. It evaluates the OraclePlanSettings[_key] BUT the key is not there right?
So it executes code to check on null for an invalid key and throws an exception.
Only by breaking out the logic as I have shown, will the excpetion not be thrown.

If statement can't change local variable

Why can't i change value with an if statement?
int amount;
string inputbalk = inputbar.Text;
if (inputbalk== string.Empty)
{
amount = Convert.ToInt32(inputbalk);
amount = 1;
}
if (inputbalk != string.Empty)
{
amount = Convert.ToInt32(inputbalk);
amount = 1;
}
int onepercent = amount/= 100;
It will see "amount" as an unassigned variable, even though I set it to 1, by two different if-statements.
If I debug, I get this:
"Error 1 Use of unassigned local variable 'amount'"
Thanks for help guys, It is fixed/solved.
Just change second if to else
if (inputbalk== string.Empty)
{
amount = Convert.ToInt32(inputbalk);
amount = 1;
}
else
{
amount = Convert.ToInt32(inputbalk);
amount = 1;
}
The compiler can't make sure that one of two if statements will work anyway, so it will throw error that your variable amount can be unassigned.
In if/else notation one of two code blocks will be done anyway, so compiler will not throw error and everything will work as you want.
There is chance of having inputbalk as null :)
if is not a loop
considering inputbalk is string, it can be a null, you don't check for it, so could happen that it's your case.
Change your code, like this:
if (string.IsNullOrEmpty(inputbalk))
{
amount = Convert.ToInt32(inputbalk);
amount = 1;
}
else
{
amount = Convert.ToInt32(inputbalk);
amount = 1;
}
Hope this helps.
The problem is that the compiler cannot see that amount is definitely assigned. You know that inputBalk can't change between the first and second time it is evaluated, and that exactly one of the if conditions will be true, but the compiler doesn't check this. It sees only that there is a path where amount isn't assigned before it is used, which is disallowed.
You should use if/else instead of testing the same condition twice.
if (...)
{
amount = 1;
}
else
{
amount = 2;
}
Now the compiler can see that every possible path through the code causes amount to be definitely assigned.
There are also a number of other advantages: the code is more concise, easier to read and more maintainable. Furthermore, there is a slight performance benefit from not doing the same check twice.
You could however also encounter an FormatException with the Convert.ToInt32() method. Consider using int.tryParse as an alternative.
Because the chances are that you won't go into any if statement and thus leaving the amount as unassigned. You will get error on this line:
int onepercent = amount /= 100;
At compile time, compiler will not be able to determine whether any of the if statement will result in true and setting of amount. To avoid this error you could do (at start) :
int amount=-1;
Now you will not get your compiler error and value of the amount will change in the if statement. P.S. ('If' is a statement not a loop)
Give this a blast:
if (!int.TryParse(inputbar.Text, out amount))
amount = 1;

Lock using atomic operations

Yes, I'm aware of that the following question could be answered with "Use the lock keyword instead" or something similar. But since this is just for "fun", I don't care about those.
I've made a simple lock using atomic operations:
public class LowLock
{
volatile int locked = 0;
public void Enter(Action action)
{
var s = new SpinWait();
while (true)
{
var inLock = locked; // release-fence (read)
// If CompareExchange equals 1, we won the race.
if (Interlocked.CompareExchange(ref locked, 1, inLock) == 1)
{
action();
locked = 0; // acquire fence (write)
break; // exit the while loop
}
else s.SpinOnce(); // lost the race. Spin and try again.
}
}
}
I'm using the lock above in a simple for loop, that adds a string to a normal List<string>, with the purpose of making the add method thread-safe, when wrapped inside the Enter method from a LowLock.
The code looks like:
static void Main(string[] args)
{
var numbers = new List<int>();
var sw = Stopwatch.StartNew();
var cd = new CountdownEvent(10000);
for (int i = 0; i < 10000; i++)
{
ThreadPool.QueueUserWorkItem(o =>
{
low.Enter(() => numbers.Add(i));
cd.Signal();
});
}
cd.Wait();
sw.Stop();
Console.WriteLine("Time = {0} | results = {1}", sw.ElapsedMilliseconds, numbers.Count);
Console.ReadKey();
}
Now the tricky part is that when the main thread hits the Console.WriteLine that prints time and number of elements in the list, the number of elements should be equal to the count given to the CountdownEvent (10000) - It works most of the time, but sometimes there's only 9983 elements in the list, other times 9993. What am I overlooking?
I suggest you take a look at the SpinLock structure as it appears to do exactly what you want.
That said, this all looks really dicey, but I'll have a stab at it.
You appear to be trying to use 0 to mean 'unlocked' and 1 to mean 'locked'.
In which case the line:
if (Interlocked.CompareExchange(ref locked, 1, inLock) == 1)
isn't correct at all. It's just replacing the locked variable with the value of 1 (locked) if its current value is the same as the last time you read it via inLock = locked (and acquiring the lock if so). Worse, it is entering the mutual exclusion section if the original value was 1 (locked), which is the exact opposite of what you want to be doing.
You should actually be atomically checking that the lock has not been taken (original value == 0) and take it if you can (new value == 1), by using 0 (unlocked) as both the comparand argument as well as the value to test the return value against:
if (Interlocked.CompareExchange(ref locked, 1, 0) == 0)
Now even if you fixed this, we also need to be certain that the List<T>.Add method will 'see' an up to date internal-state of the list to perform the append correctly. I think Interlocked.CompareExchange uses a full memory barrier, which should create this pleasant side-effect, but this does seem a little dangerous to rely on (I've never seen this documented anywhere).
I strongly recommend staying away from such low-lock patterns except in the most trivial (and obviously correct) of scenarios unless you are a genuine expert in low-lock programming. We mere mortals will get it wrong.
EDIT: Updated the compare value to 0.
Interlocked.CompareExchange returns the original value of the variable, so you want something like this:
public class LowLock
{
int locked = 0;
public void Enter( Action action )
{
var s = new SpinWait();
while ( true )
{
// If CompareExchange equals 0, we won the race.
if ( Interlocked.CompareExchange( ref locked, 1, 0 ) == 0 )
{
action();
Interlocked.Exchange( ref locked, 0 );
break; // exit the while loop
}
s.SpinOnce(); // lost the race. Spin and try again.
}
}
}
I've removed the volatile and used a full fence to reset the flag, because volatile is hard

Categories

Resources