After my previous question, I tried to fix the code but still the output is not what I expect. I tried to defined a thread safe integer:
using System;
using System.Threading;
public struct SInt
{
private int _value;
public SInt(int initialValue = 0)
{
_value = initialValue;
}
public int Value => Volatile.Read(ref _value); // Interlocked.CompareExchange(ref _value, 0, 0);
// Add a value
public int Add(int value) => Interlocked.Add(ref _value, value);
// Subtract a value
public int Subtract(int value) => Interlocked.Add(ref _value, -value);
// Multiply the value
public int Multiply(int value)
{
int initial, computed;
do
{
initial = Value;
computed = initial * value;
}
while (Interlocked.CompareExchange(ref _value, computed, initial) != initial);
return computed;
}
// Divide the value
public int Divide(int value)
{
if (value == 0)
throw new DivideByZeroException();
int initial, computed;
do
{
initial = Value;
computed = initial / value;
}
while (Interlocked.CompareExchange(ref _value, computed, initial) != initial);
return computed;
}
// Increment the value
public int Increment() => Interlocked.Increment(ref _value);
// Decrement the value
public int Decrement() => Interlocked.Decrement(ref _value);
// Overloaded operators
public static SInt operator +(SInt a, int b)
{
a.Add(b);
return a;
}
public static SInt operator -(SInt a, int b)
{
a.Subtract(b);
return a;
}
public static SInt operator *(SInt a, int b)
{
a.Multiply(b);
return a;
}
public static SInt operator /(SInt a, int b)
{
a.Divide(b);
return a;
}
public static SInt operator ++(SInt a)
{
a.Increment();
return a;
}
public static SInt operator --(SInt a)
{
a.Decrement();
return a;
}
// Equality operators
public static bool operator ==(SInt a, SInt b) => a.Value == b.Value;
public static bool operator !=(SInt a, SInt b) => a.Value != b.Value;
// Comparison operators
public static bool operator <(SInt a, SInt b) => a.Value < b.Value;
public static bool operator <=(SInt a, SInt b) => a.Value <= b.Value;
public static bool operator >(SInt a, SInt b) => a.Value > b.Value;
public static bool operator >=(SInt a, SInt b) => a.Value >= b.Value;
// Implicit conversion from int to SInt
public static implicit operator SInt(int value) => new SInt(value);
// Implicit conversion from SInt to int
public static implicit operator int(SInt sInt) => sInt.Value;
public override bool Equals(object? obj)
{
if (obj is SInt other)
{
return this == other;
}
return false;
}
public override int GetHashCode() => Value.GetHashCode();
public override string ToString() => Value.ToString();
}
Then I rewrote the program:
using System;
using System.Diagnostics;
using System.Threading;
class Program
{
static void Main(string[] args)
{
List<Thread> threads = new List<Thread>();
SInt s = 0;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i <1000; i++)
{
var t = new Thread(() =>
{
s++;
Thread.Sleep(1000);
});
t.Priority = ThreadPriority.Highest;
threads.Add(t);
t.Start();
}
foreach (var t in threads)
t.Join();
stopwatch.Stop();
Console.WriteLine($"Time: {stopwatch.ElapsedMilliseconds / 1000.0} Seconds");
Console.WriteLine(s);
Console.WriteLine(threads.Count(t => t.ThreadState == System.Threading.ThreadState.Stopped));
Console.ReadKey();
}
}
output in my laptop:
Time: 85.16 Seconds
989
1000
I expect that 989 be 1000.
What's wrong?
In C# a struct
is a value type.
Therefore when you return it e.g. in:
public static SInt operator ++(SInt a)
{
a.Increment();
return a; // <-- here a copy is returned
}
You actually return a copy.
If SInt
was a class
it would behave like you expect, because being a reference type it would return a reference to the current instance.
Note:
As @user555045 commented above even if you solve this specfic problem of using operator++
, you will still have problems when it is used in more complex expressions.