Why does msft compare Interlocked.Increment(ref uniqueId) to zero? - c#

I'm looking at the System.Threading.Tasks.TaskScheduler.Id implementation of .NET 4.0, and see the following code:
[__DynamicallyInvokable]
public int Id
{
[__DynamicallyInvokable]
get
{
if (this.m_taskSchedulerId == 0)
{
int num = 0;
do
{
num = Interlocked.Increment(ref s_taskSchedulerIdCounter);
}
while (num == 0);
Interlocked.CompareExchange(ref this.m_taskSchedulerId, num, 0);
}
return this.m_taskSchedulerId;
}
}
why does msft compare the num==0 after the interlocked? The implementation of Interlocked.Increment() says it returns the incremented value (after incrementing) so seems unnessicary to check for zero (unless your counter wraps around, but if that happens you have bigger problems that are also not resolved here.
If I were to do it, i'd simply do:
public int Id
{
get
{
if(m_taskSchedulerId==0)
{
var result = Interlocked.Increment(ref s_taskSchedulerIdCounter);
Interlocked.CompareExchange(ref m_taskSchedulerId, result, 0);
}
return m_taskSchedulerId;
}
}

but if that happens you have bigger problems
No, that's the exact reason they do this. From the Reference Source:
public Int32 Id
{
get
{
if (m_taskSchedulerId == 0)
{
int newId = 0;
// We need to repeat if Interlocked.Increment wraps around and returns 0.
// Otherwise next time this scheduler's Id is queried it will get a new value
do
{
newId = Interlocked.Increment(ref s_taskSchedulerIdCounter);
} while (newId == 0);
Interlocked.CompareExchange(ref m_taskSchedulerId, newId, 0);
}
return m_taskSchedulerId;
}
}

The invariant is that Id never returns 0, because 0 is used internally to indicate that the value should be initialized. If Id was ever 0, the next time you queried it it would be a different value.

Related

Not all code paths return a value with a while loop [duplicate]

This question already has answers here:
.NET compiler and "Not all code paths return a value"
(5 answers)
Closed 4 years ago.
The compiler is complaining that the following code snippet won't always return. I have inspected it and don't see an issue.
private int MyFunction(int b)
{
int result = -1;
while (result != 1)
{
result = MySmallFunction(out var x);
if (result == 1)
{
return x;
}
}
}
private int MySmallFunction(out int x)
{
x = 1;
return 1;
}
MySmallFunction does stuff and returns a code, 1 meaning success, and the rest is an error code.
If it returns 1, that means that the out int x has a value.
If the return value is not 1 (error code), then I want to retry.
If MySmallFunction never returns 1, the application should just be stuck in a loop forever. That shouldn't be a problem for the compiler.
I rewrote the function to this:
private int MyFunction()
{
int result = -1;
int x = int.MinValue;
while (result != 1)
{
result = MySmallFunction(out x);
}
return x;
}
private int MySmallFunction(out int x)
{
x = 1;
return 1;
}
Now x will only be returned if MySmallFunction returns a status code of 1.
In the case that your while loop doesn't trigger, there is not return instruction, you need a return at the bottom of your function outside the while loop.
As per the signature of the method MyFunction() it should return a value to the calling method in all conditions. but in your case, you are returning a value only if (result == 1) in all other case it is invalid, so you have to add a return at the end, which will return an integer. So you have to change something like this:
private int MyFunction(int b)
{
int result = -1;
while (result != 1)
{
result = MySmallFunction(out var x);
if (result == 1)
{
return x;
}
}
return 0;
}

C# Recursive Increment Decrement not working as parameters

I am using recursion to add two numbers together, By adding 1 to the first input one at a time until I have reached the value of the second.
Why does this work...
private static int AddMethod(int input1, int input2)
{
if (input2 == 0)
{
Console.WriteLine(input1);
return (input1);
}
else
{
input1++;
input2--;
return AddMethod(input1, input2);
}
}
But not this..
private static int AddMethod(int input1, int input2)
{
if (input2 == 0)
{
Console.WriteLine(input1);
return (input1);
}
else
{
return AddMethod(input1++, input2--);
}
}
I am using Visual Studio 2010 and .Net 4.0
Because return AddMethod(input1++, input2--); first passes your inputs, and THEN increments and decrements.
Try
return AddMethod(++input1, --input2);
Post fix increment works by first "assigning" the value, then incrementing the value.
Compare:
int a = 1;
int b = 1;
int x = a++;
int y = ++b;
So in your case, the value you pass to AddMethod is the unchanged value, it modifies the value of input1 and input2 after they are passed.
Because the ++ and -- operators are executed after passing the values as parameters to the function.
Your code:
return AddMethod(input1++, input2--);
Is equal to:
int result AddMethod(input1, input2);
input1++;
input2--;
return result;
Instead of all this, you could use:
return AddMethod(++input1, --input2);

Somewhat complex list sorting

I have a number of objects each with 3 numerical properties: "high", "low" and "tiebreaker". They are to be sorted as such: if an object's low is higher than another object's high, it appears before it in the list. Likewise if an object's high is lower than another's low, it appears later in the list. But in the case that two objects have conflicting ranges (eg one's high is between the other object's low and high), the tiebreaker property is considered wherein the object with the higher tiebreaker value gets placed earlier on the list.
I am specifically working with c#, but I think the ideas here are language agnostic enough such that code of any sort (no puns) would be welcome.
Also, I have worked on this myself. I have a nested for-loop that is just not working out for me so far. I'd give up some code but I'm on my phone and that makes it a chore. Besides, this is probably a fun one for you and you don't need my ugly code in your way anyhow.
Are you assuming that Min <= Tie <= Max? You do not say so in your question, and if you do not, the sort order is not well defined because it is not transitive. For instance, writing your ranges as [Min, Tie, Max], consider:
A: [5,-10, 6]
B: [0, 1, 10]
C: [2, 3, 4]
A < B (because they overlap and -10 < 1)
B < C (because they overlap and 1 < 3)
but A > C (because they don't overlap and 5 > 4)
If they are you can define a custom IComparer<Range> for your Range class, and pass it to any c# sort method.
Update and here's one such implementation.
public struct RangeWithTie<T> where T : IEquatable<T>, IComparable<T>
{
readonly T min;
readonly T max;
readonly T tie;
readonly bool isNonEmpty;
public static Range<T> Empty = new Range<T>();
public static IComparer<RangeWithTie<T>> CreateSortingComparer()
{
return new RangeWithTieComparer();
}
public RangeWithTie(T start, T tie, T end)
{
// Enfore start <= tie <= end
var comparer = Comparer<T>.Default;
if (comparer.Compare(start, end) > 0) // if start > end
{
throw new ArgumentOutOfRangeException("start and end are reversed");
}
else if (comparer.Compare(start, tie) > 0)
{
throw new ArgumentOutOfRangeException("tie is less than start");
}
else if (comparer.Compare(tie, end) > 0)
{
throw new ArgumentOutOfRangeException("tie is bigger than end");
}
else
{
this.min = start;
this.max = end;
this.tie = tie;
}
this.isNonEmpty = true;
}
public T Min { get { return min; } }
public T Max { get { return max; } }
public T Tie { get { return tie; } }
public bool IsEmpty { get { return !isNonEmpty; } }
public class RangeWithTieComparer : IComparer<RangeWithTie<T>>
{
#region IComparer<RangeWithTie<T>> Members
public int Compare(RangeWithTie<T> x, RangeWithTie<T> y)
{
// return x - y.
if (x.IsEmpty)
{
if (y.IsEmpty)
return 0;
else
return -1;
}
else if (y.IsEmpty)
{
return 1;
}
var comparer = Comparer<T>.Default;
if (comparer.Compare(y.Min, x.Max) > 0)
return -1;
else if (comparer.Compare(x.Min, y.Max) > 0)
return 1;
return comparer.Compare(x.Tie, y.Tie);
}
#endregion
}
public override string ToString()
{
if (IsEmpty)
return "Empty";
StringBuilder s = new StringBuilder();
s.Append('[');
if (Min != null)
{
s.Append(Min.ToString());
}
s.Append(", ");
if (Tie != null)
{
s.Append(Tie.ToString());
}
s.Append(", ");
if (Max != null)
{
s.Append(Max.ToString());
}
s.Append(']');
return s.ToString();
}
}
This could be used like so:
var sortedRanges = ranges.OrderBy(x => x, RangeWithTie<double>.CreateSortingComparer()).ToArray();
I didn't make the struct implement IComparer<RangeWithTie<T>> directly because ranges with identical comparisons aren't necessarily equal. For instance, [-1,0,1] and [-2,0,1] have identical comparisons but are not equal.
A quick solution, and a console application to test it. This method will return the larger of two objects. Just replace dynamic with the appropriate object type you need.
class Program
{
private static object Sort(dynamic first, dynamic second)
{
if (OverlapExists(first, second))
{
// Note: If tiebreakers are equal, the first will be returned:
return first.tiebreaker >= second.tiebreaker ? first : second;
}
else
{
// Note: Only need to test one value (just high); Since we know
// there is no overlap, the whole object (both high and low) must
// be either over or under that which it is compared to:
return first.high > second.high ? first : second;
}
}
private static bool OverlapExists(dynamic first, dynamic second)
{
return (first.low < second.high) && (second.low < first.high);
}
static void Main(string[] args)
{
dynamic first = new {name="first", high = 10,
tiebreaker = 5, low = 1 };
dynamic second = new {name="second", high = 15,
tiebreaker = 12, low = 11 };
dynamic third = new {name="third", high = 20,
tiebreaker = 9, low = 6 };
var firstResult = Sort(first, second);
var secondResult = Sort(first, third);
var thirdResult = Sort(second, third);
Console.WriteLine("1) " + first.ToString()
+ "\nVS: " + second.ToString());
Console.WriteLine("Winner: " + firstResult.name);
Console.WriteLine("\n2) " + first.ToString()
+ "\nVS: " + third.ToString());
Console.WriteLine("Winner: " + secondResult.name);
Console.WriteLine("\n3) " + second.ToString()
+ "\nVS: " + third.ToString());
Console.WriteLine("Winner: " + thirdResult.name);
Console.ReadKey();
}
}
Let’s say you have a List<T> (T being your objects with High-, Low- and Tie- Property), then you can use
list.Sort(…);
with a Comparison<T> as a Parameter. That’s a delegate that takes 2 of you objects and should return < 0, when the first instance of your object should be a head of the other instance or 0 if they are of equal order (or > 0 if the second second object should be ahead of first).
Or you could pass an custom comparer (implementing IComparer<T>) which does basically the same as the Comparison<T> but inform of an interface.
No matter what your logic is, you may implement IComparable to enable an Array or List's sorting capability. So, as the follow code shows,
public class MyStuff : IComparable<MyStuff>
{
public int High { get; set; }
public int Low { get; set; }
public int TieBreaker { get; set; }
public int CompareTo(MyStuff other)
{
// if an object's low is higher than another object's high,
// it appears before it in the list
if ((this.Low > other.High) ||
// if its high is between the other object's low and
// high then compare their tiebreaker
(this.High > other.Low && this.High < other.High &&
this.TieBreaker > other.TieBreaker))
return 1;
else if (this.Low == other.High)
return 0;
else
return -1;
}
}
The basic idea is CompareTo returns either 1 (move this before other), 0 (retain both positions) or -1 (move this after other), depending on your ordering logic.
See IComparable<T>
class DataObject : IComparable<DataObject>
{
public double High, Low, Tiebreaker;
public int CompareTo(DataObject obj)
{
// this doesn't seem to make sense as a range sort, but seems to match your question...
// low > another high
if (this.Low != obj.High)
return this.Low.CompareTo(obj.High);
// otherwise sort tiebreaker ascending
else this.TieBreaker.CompareTo(obj.TieBreaker);
}
}
used as
var items = new[] { new DataObject(1,2,3), new DataObject(4,5,6) };
Array.Sort<DataObject>(items);
// items is now sorted

Incrementing integer from ArrayList in method won't work?

string popIt(System.Collections.ArrayList pool,ref int spin) //"EMPTY"/str;++/"OVER"
{
if (pool.Count == 0)
{ return "EMPTY"; }
else
{
if (spin < pool.Count) { spin += 1; return pool[spin - 1].ToString(); }
else { return "OVER"; }
}
}
popIt(pools[0], spiners[0]);
This won't increment int spiners[0] in ArrayList spinners, it will only increment spin in the method, like VB.NET ByVal. I tried using ref keyword, but I get few errors, how to do this?
So you can do like this:
int spin=spiners[0];
popIt(pools[0], ref spin);
spiners[0]=spin;
Thats will work, if I correctly understand what you need.

in what situation will an item in System.Collections.Generic.List not be removed successfully?

in what situation will an item in System.Collections.Generic.List not be removed successfully?
From http://msdn.microsoft.com/en-us/library/cd666k3e.aspx:
true if item is successfully removed;
otherwise, false. This method also
returns false if item was not found in
the List(Of T).
The way they phrase it makes me think that it is possible that a Remove operation on an item found in the List(Of T) could actually fail, hence this question.
Looking at the System.Collections.Generic.List source in Reflector, it would appear that the item not being found in the collection is indeed the only way for Remove to return false.
int index = this.IndexOf(item);
if (index >= 0)
{
this.RemoveAt(index);
return true;
}
return false;
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public bool Remove(T item)
{
int index = this.IndexOf(item);
if (index >= 0)
{
this.RemoveAt(index);
return true;
}
return false;
}
Code above via reflector. Will only not be removed if it wasn't in the collection. I'm guessing a documentation/language discrepancy.
Yes it can, if you are trying to remove an item that isn't in the list - it is classed as a fail and returns false to show you that nothing was removed.
This can be useful if you then want to do other code if something was actually removed.
Update: if your class implements IEquality and that throws an exception, the code lets the throw occur, as in it doesn't get a chance to return.
Coupled with others posting the reflected source, returning false is only when it cannot find an item.
Update: further to other people's source. If you look at the IndexOf chain of methods, you will see that it boils down to equality and does nothing special.
List.Remove:
public bool Remove(T item)
{
int num = this.IndexOf(item);
if (num >= 0)
{
this.RemoveAt(num);
return true;
}
return false;
}
List.IndexOf:
public int IndexOf(T item)
{
return Array.IndexOf<T>(this._items, item, 0, this._size);
}
Array.IndexOf:
public static int IndexOf<T>(T[] array, T value, int startIndex, int count)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (startIndex < 0 || startIndex > array.Length)
{
throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
if (count < 0 || count > array.Length - startIndex)
{
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
}
return EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count);
}
EqualityComparer.IndexOf:
internal virtual int IndexOf(T[] array, T value, int startIndex, int count)
{
int num = startIndex + count;
for (int i = startIndex; i < num; i++)
{
if (this.Equals(array[i], value))
{
return i;
}
}
return -1;
}
All code from ILSpy, no thanks to Red Gate :-)
In Mono's source code for comparison:
https://github.com/mono/mono/raw/master/mcs/class/corlib/System.Collections.Generic/List.cs
public bool Remove (T item)
{
int loc = IndexOf (item);
if (loc != -1)
RemoveAt (loc);
return loc != -1;
}
So, the documentation is overly fuzzy

Categories

Resources