This question "How to get the CPU Usage in C#?" shows some of the ways to get the current CPU usage (%) of a computer in .NET.
Since the CPU usage fluctuates quite frequently, I think the current CPU usage is often not a good indicator of how busy a computer is (e.g. for scheduling or load balancing purpose). Is there an efficient way to get the average CPU usage in last x minute, e.g. last 5 minutes?
I am thinking of something like a method GetAverageCpuUsage(int period) that can be called by a load balancing or scheduling module.
Actually that is exactly what PerformanceCounter from the 2nd most upvoted answer in the other question does, they are just measuring over 1 second.
The % it gives you is the average % of cpu seance the last NextValue() was made on the counter. So if you want the average cpu over the last 5 min, just call NextValue() only once every 5 min.
Here is a good article explaining how to use the performance counters.
The answers above give a pretty good example for a way to calculate CPU usage.But I would like to point out something that is incorrect and was misled. The SubtractTimes function needs to be slightly different.
private UInt64 SubtractTimes(ComTypes.FILETIME a, ComTypes.FILETIME b)
{
UInt64 aInt = ((UInt64)(a.dwHighDateTime << 32)) | (UInt32)a.dwLowDateTime;
UInt64 bInt = ((UInt64)(b.dwHighDateTime << 32)) | (UInt32)b.dwLowDateTime;
return aInt - bInt;
}
NOTICE THE UINT32 for the lowDateTime. This is because, atleast in C#, the comtype.FILETIME struct casts the DWORD to an int32, so if the value is more than MAX signed Int you see a negative value which should never be the case. If you cast this directly to "UINT64" type, internally for preserving sign this is converted to Int64 first and then converted to UInt64 so you see an incorrect value. Instead You want to cast the lowDateTime to a Uint32 type to get rid of the negative sign, and then cast to UInt64 (this would happen automatically since it is part of | operation). Same should hold for the dwHighDateTime conponent but thats fine since it should not be more than MaxInt usually (well, that again depends on your usecase).
try something like:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using ComTypes = System.Runtime.InteropServices.ComTypes;
using System.Threading;
using System.Diagnostics;
namespace example1
{
public class CpuUsage
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetSystemTimes(
out ComTypes.FILETIME lpIdleTime,
out ComTypes.FILETIME lpKernelTime,
out ComTypes.FILETIME lpUserTime
);
ComTypes.FILETIME _prevSysKernel;
ComTypes.FILETIME _prevSysUser;
TimeSpan _prevProcTotal;
Int16 _cpuUsage;
DateTime _lastRun;
long _runCount;
public CpuUsage()
{
_cpuUsage = -1;
_lastRun = DateTime.MinValue;
_prevSysUser.dwHighDateTime = _prevSysUser.dwLowDateTime = 0;
_prevSysKernel.dwHighDateTime = _prevSysKernel.dwLowDateTime = 0;
_prevProcTotal = TimeSpan.MinValue;
_runCount = 0;
}
public short GetUsage()
{
short cpuCopy = _cpuUsage;
if (Interlocked.Increment(ref _runCount) == 1)
{
if (!EnoughTimePassed)
{
Interlocked.Decrement(ref _runCount);
return cpuCopy;
}
ComTypes.FILETIME sysIdle, sysKernel, sysUser;
TimeSpan procTime;
Process process = Process.GetCurrentProcess();
procTime = process.TotalProcessorTime;
if (!GetSystemTimes(out sysIdle, out sysKernel, out sysUser))
{
Interlocked.Decrement(ref _runCount);
return cpuCopy;
}
if (!IsFirstRun)
{
UInt64 sysKernelDiff = SubtractTimes(sysKernel, _prevSysKernel);
UInt64 sysUserDiff = SubtractTimes(sysUser, _prevSysUser);
UInt64 sysTotal = sysKernelDiff + sysUserDiff;
Int64 procTotal = procTime.Ticks - _prevProcTotal.Ticks;
if (sysTotal > 0)
{
_cpuUsage = (short)((100.0 * procTotal) / sysTotal);
}
}
_prevProcTotal = procTime;
_prevSysKernel = sysKernel;
_prevSysUser = sysUser;
_lastRun = DateTime.Now;
cpuCopy = _cpuUsage;
}
Interlocked.Decrement(ref _runCount);
return cpuCopy;
}
private UInt64 SubtractTimes(ComTypes.FILETIME a, ComTypes.FILETIME b)
{
UInt64 aInt = ((UInt64)(a.dwHighDateTime << 32)) | (UInt64)a.dwLowDateTime;
UInt64 bInt = ((UInt64)(b.dwHighDateTime << 32)) | (UInt64)b.dwLowDateTime;
return aInt - bInt;
}
private bool EnoughTimePassed
{
get
{
const int minimumElapsedMS = 250;
TimeSpan sinceLast = DateTime.Now - _lastRun;
return sinceLast.TotalMilliseconds > minimumElapsedMS;
}
}
private bool IsFirstRun
{
get
{
return (_lastRun == DateTime.MinValue);
}
}
}
}
after using it so well in ur code:
CpuUsage _cu = new CpuUsage();
string cpuUsage = _cu.GetUsage();
have helped on something
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Management;
using System.Timers;
using System.Threading;
class Program
{
static class PerfStatic
{
private static float[] m_list;
private static int index = 0;
private static int count = 60;
private static float val = 0;
private static bool inited = false;
private static bool ready = false;
private static PerformanceCounter cpuCounter = new PerformanceCounter("Processor Information", "% Processor Utility", "_Total");
public static void tick(Object source, ElapsedEventArgs e)
{
val = cpuCounter.NextValue();
index++;
if (index >= count)
{
index = 0;
ready = true;
}
m_list[index] = val;
}
public static float CPU1MinAverage
{
get
{
if (!inited)
{
Init();
inited = true;
return 100;
}
if (!ready)
return 100;
return m_list.Average();
}
}
public static void Init()
{
m_list = new float[count];
var aTimer = new System.Timers.Timer(1000);
aTimer.Elapsed += tick;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
}
static void Main(string[] args)
{
while (true)
{
Console.WriteLine(PerfStatic.CPU1MinAverage);
Thread.Sleep(1000);
}
}
}
Static class for 1 minute average, returns 100 if not enough data, needs to be called to start collecting data, modify for your needs.
You also need nuget extension on .net 6 - System.Diagnostics.PerformanceCounter
Related
I attempting to create a program that uses multiple methods that would print out base numbers, exponents, and their resulting solutions. I am trying to get it to run and it's nearly completed, but I am encountering a couple issues. The code itself seems to run, but doesn't appear to print out on Visual Studio. I did run it on an online compiler and got this as an output:
It seems I am missing something in my code, but I am unclear as to what I may be missing. This is the code I have created for the project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Project
{
class Program
{
static void Main(string[] args)
{
//Our initialized variables.
int intMinBase = 1;
int intMaxBase = 100;
int intMinExpo = 1;
int intMaxExpo = 10;
//Our arrays for the project, all at a length of 5.
long[] baseNumbers = new long[5];
long[] exponents = new long[5];
long[] results = new long[5];
//Randomize the baseNumbers and exponents!
Random randInt = new Random();
for (long i = 0; i < 5; i++)
{
baseNumbers[i] = randInt.Next(intMinBase, intMaxBase);
exponents[i] = randInt.Next(intMinExpo, intMaxExpo);
}
PrintArrays(baseNumbers, exponents, results);
}
//This is potentially experimental code for the Power Method.
public static int Power(int baseNum, int exponent)
{
int answer;
if (exponent == 1)
{
answer = 1;
}
else
{
answer = baseNum * Power(baseNum, exponent - 1);
}
return answer;
}
//The new method to be printed. Is this the correct manner to display this?
public static void PrintArrays(long[] baseNum, long[] exponent, long[] result)
{
Console.WriteLine($"Base\tExponent\tResult");
for (int print = 0; print < result.GetUpperBound(0); print++)
{
Console.WriteLine(baseNum[print]+"\t"+exponent[print]+"\t"+result[print]);
}
}
}
}
My question is mainly am I missing something and why isn't it appearing to print in Visual Studio yet it's appearing on an online compiler? I suspect the answer to the first part of the question has to do with the methods I used, but I am unsure.
First error: Nowhere is the method Power called and nowhere is the array results filled.
Solution example:
for (long i = 0; i < 5; i++)
{
baseNumbers[i] = randInt.Next(intMinBase, intMaxBase);
exponents[i] = randInt.Next(intMinExpo, intMaxExpo);
results[i] = Power(baseNumbers[i], exponents[i]);
}
I've written a BouncyCastle style threaded seeder and was wondering about the predictability of the data the program generates.
The reason I'm not simply using BouncyCastle is because security isn't a concern, I don't want to use a whole library just for one function, and this code is MUCH faster.
The idea is to make several threads which operate on a circular buffer (a simple array), where each thread performs a different operation on the data in the buffer. The randomness comes from thread scheduling irregularities in the OS.
How much randomness can I expect from a mechanism like this?
using System;
using System.Threading;
class ThreadedSeeder
{
static public ulong[] buffer = new ulong[1024];
static public bool doThread = true;
public ThreadedSeeder()
{
MakeThread(Add);
MakeThread(Multiply);
MakeThread(Xorshift);
Thread.Sleep(10);
doThread = false;
}
static private void MakeThread(ThreadStart a)
{
Thread b = new Thread(a)
{
Priority = ThreadPriority.Lowest
};
b.Start();
}
static private void Add()
{
int i = 0;
while (doThread)
{
buffer[i & 1023] += (ulong)DateTime.UtcNow.Ticks;
i++;
}
}
static private void Multiply()
{
int i = 0;
while (doThread)
{
buffer[i & 1023] *= 6364136223846793005;
i++;
}
}
static private void Xorshift()
{
int i = 0;
while (doThread)
{
ulong y = buffer[i & 1023];
y ^= (y << 13);
y ^= (y >> 17);
y ^= (y << 5);
buffer[i & 1023] = y;
i++;
}
}
}
I think the randomness will be pretty high, as the order and scheduling of the threads is never guaranteed (unless you are using synchronization mechanisms).
Each time you'll run the code you'll probably get different results in the array after executing.
Hope it helps!
im trying to create a timer to "tick" and created this timer with a little google help.
It works perfectly in console, but when i added it in a website, it seems my computer is running at full capasity, and the site is loading slowly and not function properly.
Can i use this or do i need to start over?
namespace ticket
{
class Program
{
public static int counttick = 0;
public static int ticks = 0;
static void LoopingFunction()
{
while (counttick <= 20)
{
int dwStartTime = System.Environment.TickCount;
while (true)
{
if (System.Environment.TickCount - dwStartTime > 1000) break; //1000 milliseconds
}
counttick++;
if (counttick == 20)
{
ticks++;
counttick = 0;
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
Label2.Text = "Ticks: " + Convert.ToString(ticks);
LoopingFunction();
}
}
}`
Remove:
while (true)
{
if (System.Environment.TickCount - dwStartTime > 1000) break; //1000 milliseconds
}
And use:
System.Threading.Sleep(1000);
Try System.Threading.Timer class.
In web applications i don't recommend using static variables, because you really never know when you IIS will recycle the app pool and you static varitable will become 0. rather you should try something to persistence storage. and use to Try System.Threading.Timer class to update the value in may be a Database table or some file.
Regards.
I'll just give another approach. I needed a similar tick loop that runs at about 25 frames per second. I have a class called ApplicationLoop which, when constructed starts a thread. That thread is my application loop. (Hence the obvious class name.)
So I have a few constants, to determine my frame rate, and a frame-skip fallback value. Basically, when a task takes more time than 40ms (1000 / 25 = 40), I loop through all the tasks again to "catch-up". But I only do this a number of times.
private const int MAX_FRAMESKIP = 5;
private const int UPDATE_SKIP_TICKS = 1000 / UPDATE_TICKS_PER_SECOND;
private const int UPDATE_TICKS_PER_SECOND = 25;
My thread function:
private void UpdateLoop()
{
ulong ticks = 0UL;
_isRunning = true;
var next = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
while (_isRunning)
{
var now = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
int loops = 0;
while ((now > next) && _isRunning && (loops < MAX_FRAMESKIP))
{
ProcessTasks(ticks);
next += UPDATE_SKIP_TICKS;
loops++;
ticks++;
}
AccurateSleep(1);
}
}
My class contains a Subscribe() function which takes a delegate. I store that callback into a List and the ProcessTasks() function calls each subscribed function.
You can replace the AccurateSleep() function with a simple Thread.Sleep(1) call, but be aware that the default time-slice for a sleep is about 15ms.
[DllImport("winmm.dll")]
private static extern uint timeBeginPeriod(uint period);
[DllImport("winmm.dll")]
private static extern uint timeEndPeriod(uint period);
private static void AccurateSleep(int sleep)
{
timeBeginPeriod(1);
Thread.Sleep(sleep);
timeEndPeriod(1);
}
Edit: After getting five downvotes but no comments saying anything about why, I've tried to reformulate the question. I can only assume the votes are because people see a lot of text and maybe think there isn't even a question in here.
I've written code that (mis)behaves rather strangely. It seems the code doesn't run the same way on other's computers, so please don't get mad at me if you can't reproduce the problem.
I had a look, just for fun, at the frequencies with which different bytes occur in GUIDs. I had noticed that the string representations of guids always contained "4". Rather than read about it on Wikipedia I tried to think about what it might be, as it can be fun to do a little "original research" and do your own thinking once in a while. (And then read the wiki afterwards!)
The strange issue on my machine happens when I try to use the "burst" feature. Provided it is reproducible in your environment, you can re-create it by running the app and hitting B. This is supposed to result in a burst of 100 steps (i.e. make 100 new guids, updating the displayed frequencies only at the end of the burst, because writing to the console is so ridiculously slow). But it actually results in just a single step!
I set a breakpoint in ProcessKey() where the burst variable is assigned. When I step out of the method, I notice in Debug Output that a thread exits. This is not a coincidence; it happens reliably every time. Then my watches show me the burst variable that was just assigned to 1000 in the previous step... has value 0.
Why does this happen? Did I do something wrong? I notice there is no attribute anywhere specifying STA, but I've never really had a clue what these things are anyway and I haven't removed anything from the console application template I used (with VS-2011 developer preview, though unlike Redmond I live in 2012 now)...
Finally: The app moves the cursor back and overwrites the text again and again. This doesn't work well if you can't make the console window high enough to show all the output at once, so you may want to fiddle with the console font (or change the width of the console, the app should change accordingly though I haven't tested). The pattern becomes completely regular (on my machine at least!) with a 4-column output (if your console is 80 chars wide you'll get 4 columns).
Code to reproduce (or not, as the case may be):
using System;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static bool running, exit;
static int burst;
static long guidCount = 0;
static long[] counts = new long[256];
static DateTime nextReport = DateTime.MinValue;
static readonly TimeSpan reportInterval = TimeSpan.FromSeconds(0.25);
static void Main(string[] args)
{
Console.WindowHeight = (int)(0.8*Console.LargestWindowHeight);
WriteLine(ConsoleColor.White, "X - Exit | P - Pause | S - Step (hold for Slow) | B - Burst\r\n");
WriteLine("Auto-reporting interval = {0}.", reportInterval);
Guid guid;
byte[] bytes;
var cursorPos = new CursorLocation();
while (!exit)
{
if (Console.KeyAvailable)
{
ProcessKey(Console.ReadKey(true));
}
if (running || burst > 0)
{
guid = Guid.NewGuid();
bytes = guid.ToByteArray();
++guidCount;
for (int i = 0; i < 16; i++)
{
var b = bytes[i];
++counts[b];
}
if (burst > 0) --burst;
if (burst == 0 || DateTime.Now > nextReport)
{
burst = -1;
cursorPos.MoveCursor();
ReportFrequencies();
}
}
else
Thread.Sleep(20);
}
}
static void ProcessKey(ConsoleKeyInfo keyInfo)
{
switch (keyInfo.Key)
{
case ConsoleKey.P:
running = !running;
break;
case ConsoleKey.B:
burst = 100;
break;
case ConsoleKey.S:
burst = 1;
break;
case ConsoleKey.X:
exit = true;
break;
}
}
static void ReportFrequencies()
{
Write("\r\n{0} GUIDs generated. Frequencies:\r\n\r\n", guidCount);
const int itemWidth = 9;
int colCount = Console.WindowWidth / (itemWidth*2);
for (int i = 0; i < 256; i++)
{
var f = (double)counts[i] / (16 * guidCount);
Write(RightAdjust(itemWidth, "{0:x}", i));
Write(GetFrequencyColor(f), " {0:p}".PadRight(itemWidth), f);
if ((i + 1) % colCount == 0) Write("\r\n");
}
nextReport = DateTime.Now + reportInterval;
}
static ConsoleColor GetFrequencyColor(double f)
{
if (f < 0.003) return ConsoleColor.DarkRed;
if (f < 0.004) return ConsoleColor.Green;
if (f < 0.005) return ConsoleColor.Yellow;
return ConsoleColor.White;
}
static string RightAdjust(int w, string s, params object[] args)
{
if (args.Length > 0)
s = string.Format(s, args);
return s.PadLeft(w);
}
#region From my library, so I need not include that here...
class CursorLocation
{
public int X, Y;
public CursorLocation()
{
X = Console.CursorLeft;
Y = Console.CursorTop;
}
public void MoveCursor()
{
Console.CursorLeft = X;
Console.CursorTop = Y;
}
}
static public void Write(string s, params object[] args)
{
if (args.Length > 0) s = string.Format(s, args);
Console.Write(s);
}
static public void Write(ConsoleColor c, string s, params object[] args)
{
var old = Console.ForegroundColor;
Console.ForegroundColor = c;
Write(s, args);
Console.ForegroundColor = old;
}
static public void WriteNewline(int count = 1)
{
while (count-- > 0) Console.WriteLine();
}
static public void WriteLine(string s, params object[] args)
{
Write(s, args);
Console.Write(Environment.NewLine);
}
static public void WriteLine(ConsoleColor c, string s, params object[] args)
{
Write(c, s, args);
Console.Write(Environment.NewLine);
}
#endregion
}
}
Ehem. I tried running the code at my HTPC, a different computer from the one I coded this on, and now I cannot reproduce the problem. That is, I do observe the burst leading to just a step, but that is due to a logical error in my code (when the report interval is reached it sets burst to -1). It's hard to believe I did not set my breakpoint, stepped through, and saw the variable get destroyed, because I know how weird that would be and tried several times to be sure I saw what I thought I saw. But it's also hard to believe I had stumbled upon such a weird and deep bug in the framework/clr, especially considering that my code had a bug that causes the thing that got me attaching the debugger in the first place..
In any case, I'll mark it as closed. And post the revised code here if anyone wants to play with it. I've fixed the bug and made the output a bit more compact so it works better on less generous screens than the 22" full-HD_one I did this on. It now uses 8 columns regardless of the console width, on the probably safe assumption that most people use standard 80-char width, into which 8 columns now fit.
If anyone would care run this and post their findings (just press P to quickly get stable frequencies, the step/burst thing is for silly stuff like seeing what the distribution looks like after fewer generations). On my HTPC, I get this result:
0x00 - 0x3f 0.34%
0x40 - 0x4f 0.73%
0x50 - 0x7f 0.34%
0x80 - 0xbf 0.44%
0xc0 - 0xff 0.34%
This means: Bytes 0x00 to 0x3f each made up 0.34% of all the bytes in all the guids generated (509,194 in this particular case, but I get this result every time with more than 100,000 guids or so). There are 3 very distinct groups, and maybe if I now go and read about Guids on wikipedia I will understand why that is. But it wouldn't be as much fun to do this if my "discovery" was something I knew before I began. :)
using System;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static bool running, exit;
static int burst;
static long guidCount = 0;
static long[] counts = new long[256];
static DateTime nextReport = DateTime.MinValue;
static readonly TimeSpan reportInterval = TimeSpan.FromSeconds(1);
static void Main(string[] args)
{
Console.WindowHeight = (int)(0.8 * Console.LargestWindowHeight);
WriteLine(ConsoleColor.White, "X - Exit | P - Run/Pause | S - Step (hold for Slow) | B - Burst");
WriteLine("Press P, S or B to make something happen.", reportInterval);
Guid guid;
byte[] bytes;
var cursorPos = new CursorLocation();
while (!exit)
{
if (Console.KeyAvailable)
{
ProcessKey(Console.ReadKey(true));
}
if (running || burst > 0)
{
guid = Guid.NewGuid();
bytes = guid.ToByteArray();
++guidCount;
for (int i = 0; i < 16; i++)
{
var b = bytes[i];
++counts[b];
}
if (burst > 0) --burst;
if (burst == 0 && DateTime.Now > nextReport)
{
cursorPos.MoveCursor();
ReportFrequencies();
}
}
else
Thread.Sleep(20);
}
}
static void ProcessKey(ConsoleKeyInfo keyInfo)
{
switch (keyInfo.Key)
{
case ConsoleKey.P:
running = !running;
break;
case ConsoleKey.B:
burst = 100;
break;
case ConsoleKey.S:
burst = 1;
break;
case ConsoleKey.X:
exit = true;
break;
}
}
static void ReportFrequencies()
{
Write("\r\n{0} GUIDs generated. Frequencies (%):\r\n\r\n", guidCount);
const int itemWidth = 11;
const int colCount = 8; // Console.WindowWidth / (itemWidth + 2);
for (int i = 0; i < 256; i++)
{
var f = (double)counts[i] / (16 * guidCount);
var c = GetFrequencyColor(f);
Write(c, RightAdjust(3, "{0:x}", i));
Write(c, " {0:0.00}".PadRight(itemWidth), f*100);
if ((i + 1) % colCount == 0) Write("\r\n");
}
nextReport = DateTime.Now + reportInterval;
}
static ConsoleColor GetFrequencyColor(double f)
{
if (f < 0.003) return ConsoleColor.DarkRed;
if (f < 0.004) return ConsoleColor.Green;
if (f < 0.005) return ConsoleColor.Yellow;
return ConsoleColor.White;
}
static string RightAdjust(int w, string s, params object[] args)
{
if (args.Length > 0)
s = string.Format(s, args);
return s.PadLeft(w);
}
#region From my library, so I need not include that here...
class CursorLocation
{
public int X, Y;
public CursorLocation()
{
X = Console.CursorLeft;
Y = Console.CursorTop;
}
public void MoveCursor()
{
Console.CursorLeft = X;
Console.CursorTop = Y;
}
}
static public void Write(string s, params object[] args)
{
if (args.Length > 0) s = string.Format(s, args);
Console.Write(s);
}
static public void Write(ConsoleColor c, string s, params object[] args)
{
var old = Console.ForegroundColor;
Console.ForegroundColor = c;
Write(s, args);
Console.ForegroundColor = old;
}
static public void WriteNewline(int count = 1)
{
while (count-- > 0) Console.WriteLine();
}
static public void WriteLine(string s, params object[] args)
{
Write(s, args);
Console.Write(Environment.NewLine);
}
static public void WriteLine(ConsoleColor c, string s, params object[] args)
{
Write(c, s, args);
Console.Write(Environment.NewLine);
}
#endregion
}
}
Post your results, ladies and gentlemen. :)
I took upon myself to present my team with a situation where a bug would be introduced by the rearrangement of instructions, however my understanding of CPUs, CLR, and JIT is quite amateurish and I did not manage to pull off a good example.
Below I show what is the best I came up with, so please look at the code snippet to understand what I am talking about from here on.
The main point is in thread2's if statement, if it ever happens - it means that the instructions were rearranged. if i manually rearrange the instructions in thread 1 or in thread 2 -> the printing will happened(even if you you swap c.x and c.y reads in thread 2, it will print due to a race condition).
My idea was to force a rearrangement of writes of x and z by making the variables which are placed farther apart integers thinking it could write them both withing one cpu cycle due to the 8 byte word size, instead of it being 3 cycles of writing 4 -> 8 -> 4 bytes. (I know it is not actually 3 cpu cycles, unfortunately, I don't know anything about assembly.) I even tried as a last resort to put it in a struct, thinking that would force some kind of an optimization from JIT.
Any help would be appreciated, because I am very eager to make it work. (I have also tried to follow the examples shown in the ebook by Joseph Albahari, but those did not work, this is why i tried to make a more sophisticated example.) I also did not forget compiling in Release for x64 instruction set.
Code:
public class Program
{
public static void Main()
{
var stopWatch = new Stopwatch();
for (var i = 0; i < 100000000; i++)
{
var delegates = new MultiTreadingDelegates(i);
Task.Run(delegates.Thread1);
Task.Run(delegates.Thread2);
}
Console.WriteLine("finished");
Console.ReadKey();
}
}
public class MultiTreadingDelegates
{
private int i = 0;
private Container container = new Container();
public MultiTreadingDelegates(int i)
{
this.i = i;
}
public void Thread1()
{
container.X = 10000000;
container.Z = 6000000000;
container.Y = 20000000;
}
public void Thread2()
{
int y = container.Y;
long z = container.Z;
int x = container.X;
if (x != 0 && z == 0 && y != 0)
{
System.Console.WriteLine($"i = {i}{Environment.NewLine}"
+ $"x = {x}{Environment.NewLine}"
+ $"z = {z}{Environment.NewLine}"
+ $"y = {y}{Environment.NewLine}"
);
}
}
}
public struct Container
{
public int X;
public long Z;
public int Y;
}
Inspired by the lecture of Sasha Goldshtein - a video i was given as a comment to my question - I have managed to pull off and example of reordering on an Intel machine(code below)! I thank everyone once again for their help.
class Program
{
static void Main(string[] args)
{
Task.Run(DelegatesUsingPetersons.Thread1);
Task.Run(DelegatesUsingPetersons.Thread2).GetAwaiter().GetResult();
}
}
static class DelegatesUsingPetersons
{
private static long x = 0;
private static long y = 0;
private static bool flag1 = false;
private static bool flag2 = false;
public static void Thread1()
{
while (true)
{
flag1 = true;
/*Thread.MemoryBarrier();*/ //Uncomment to fix locking mechanism
if (flag2 == false)
{
x++;
y++;
}
flag1 = false;
}
}
public static void Thread2()
{
long lx = 0;
long ly = 0;
while (true)
{
flag2 = true;
/*Thread.MemoryBarrier();*/ //Uncomment to fix locking mechanism
if (flag1 == false)
{
lx = x;
ly = y;
}
flag2 = false;
if (lx != ly)
{
Console.WriteLine($"lx={lx}, ly={ly} - OMG this cannot happen!");
}
}
}
}
If you want to juxtapose it with a working "more traditional" code, here is the same kind of code just without Mr.Peterson doing all the fancy algorithmic witchcraft
static class DelegatesUsingLock
{
private static long x = 0;
private static long y = 0;
private static object loq = new object();
public static void Thread1()
{
while (true)
{
if (Monitor.TryEnter(loq))
{
x++;
y++;
Monitor.Exit(loq);
}
}
}
public static void Thread2()
{
long lx = 0;
long ly = 0;
while (true)
{
if (Monitor.TryEnter(loq))
{
lx = x;
ly = y;
Monitor.Exit(loq);
}
if (lx != ly)
{
Console.WriteLine($"lx={lx}, ly={ly} - This Never Happens");
}
}
}
}