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!
Related
I have a very specific and demanding workload I am trying to multithreaded. This is very new to me so I am struggling to find an effective solution.
Program Description: UpdateEquations() is cycling through a list of mathematical functions to update the coordinates of rendered lines. By default, func.Count = 3, so this will call CordCalc() 1500 times every frame. I am using NClac to parse a function string and write the result to the Function list, which will later be used before the end of the frame (irrelevant).
Goal: I want to put each cycle of the for(int a) loop inside its own thread. Since for(int a) will only loop 3 times, I just need to start three threads. I cannot continue the for(int i) loop until for(int a) is fully calculated. I am calculating a very large about of small tasks so it would be too expensive to assign each task to the thread.
What I am currently trying to do: I am trying to use a ThreadPool queue, however I'm not sure how to wait for them all to finish before continuing onto the next for(int i) iteration. Furthermore, while the program compiles and executes, the performance is disastrous. Probably %5 of my original performance. I am not sure if creating a "new WaitCallback" is expensive or not. I was looking for a way to predefined threads somehow so that I don't have to reinitialize them 1500 times a frame. (Which is what I suspect the issue is).
Other things I've tried: I tried using new Thread(() => CordCalc(a, i)); however this seemed to have much worse performance. I saw online somewhere that using a ThreadPool would be less expensive.
(This code is shortened for readability and relevance)
public List<Function> func;
private Expression[] exp;
private int lines_i;
private int lines_a;
public void Start()
{
func = new List<Function>();
exp = new Expression[func.Count];
for (int i = 0; i < func.Count; i++) exp[i] = new Expression(func[i].function);
}
//Calculate
public void CordCalc(object state)
{
for (int b = 0; b < func.Count; b++)
exp[lines_a].Parameters[func[b].name] = func[b].mainCords[lines_i - 1];
exp[lines_a].Parameters["t"] = t;
try
{
func[lines_a].mainCords[lines_i] = Convert.ToSingle(exp[lines_a].Evaluate());
}
catch
{
Debug.Log("input Error");
func[lines_a].mainCords[lines_i] = 0;
}
}
private void UpdateEquations()
{
//Initialize equations
for (int a = 0; a < func.Count; a++)
{
func[a].mainCords[0] = t;
}
lines_i = 1;
for (int i = 1; i < 500; i++)
{
lines_a = 0;
for (int a = 0; a < func.Count; a++)
{
//Calculate
ThreadPool.QueueUserWorkItem(new WaitCallback(CordCalc));
//This was something else that I tried, which gave worse results:
//threads[a] = new Thread(() => CordCalc(a, i));
//threads[a].Start();
//t.Join();
//This was my original method call without multithreading
//func[a].mainCords[i] = CordCalc(a, i);
lines_a++;
}
lines_i++;
}
private void FixedUpdate()
{
t += step * (2 + step) * 0.05f;
UpdateEquations();
}
//Function List
public class Function
{
public string name;
public string function;
public float[] mainCords;
//Constructor
public Function(string nameIn, string funcIn)
{
name = nameIn;
function = funcIn;
}
public void SetSize(int len)
{
mainCords = new float[len];
}
}
I've been struggling with Parallel.For and local variable. I'm trying to update percentages in a console app from a parallel for. I add page in multiple document and I would like an update on the percentage for each document.
Here's my attempt so far :
I'm taking the number of the line with Console.CursorTop, and I want to pass it to a method who's gonna override the line.
Loop from Program.cs
Parallel.For(0, generationFile.nbOfFile, optionsParallel,
i =>
{
string fileName = $"{tmpDirectoryPath}/{i + 1}_{guid}.pdf";
AddPage(fileName, generationFile, i);
});
The AddPage method
private static void AddPage(string fileName, GenerationFile generationFile, int i)
{
var cursorPosition = Console.CursorTop;
//Ajout des pages
for (int j = 0; j < generationFile.SizeMaxFile; j++)
{
Page page = Page.Create(outDoc, size);
AddText(outDoc, page, font, 14, i, fileName, j, generationFile.SizeMaxFile);
for (int k = 0; k < 292; k++)
{
AddImage(outDoc, page, 30, 30);
}
outDoc.Pages.Add(page);
ConsoleManager.UpdateConsole(i, j, cursorPosition, generationFile);
}
}
The UpdateConsole method
public static void UpdateConsole(int fileNumber, double progression, int cursorPosition, GenerationFile generationFile)
{
progression = (progression / 100) * generationFile.ArchiveESC;
Console.ForegroundColor = ConsoleColor.White;
Console.SetCursorPosition(0, cursorPosition);
Console.WriteLine($"\rFichier n°{fileNumber + 1}/{generationFile.SizeMaxFile} en cours de création : {progression}% ", Console.ForegroundColor);
}
I think everything works fine, except for the cursorPosition who take one value at the beginning and never change, so the same line is updated. I understand that there is something to do with local and/or shared variable, but I'm fairly new in parallel processing so even with the other threads on this topic and the MSDN, I don't understand what to do.
The way I prefer to handle progress reporting is to have all worker threads report to a shared progress field, and have a separate timer that reads this fields and reports the progress to the user. This lets me control how often progress is reported, regardless of how fast items are processed. I also want an abstraction layer that allows different ways to report progress. After all, the same method might be used from console, the UI, or not at all.
For example something like this:
public interface IMyProgress
{
void Increment(int incrementValue);
}
public sealed class MyProgress : IMyProgress, IDisposable
{
private readonly int totalItems;
private readonly Timer myTimer;
private volatile int progress;
private int lastUpdatedProgress;
public MyProgress(TimeSpan progressFrequency, int totalItems)
{
this.totalItems = totalItems;
myTimer = new Timer(progressFrequency.TotalMilliseconds);
myTimer.Elapsed += OnElapsed;
myTimer.Start();
}
private void OnElapsed(object sender, ElapsedEventArgs e)
{
var currentProgress = progress;
if (lastUpdatedProgress != currentProgress)
{
lastUpdatedProgress = currentProgress;
var percent = currentProgress * 100 / (double)totalItems;
Console.Write($"\rWork progress: {percent}%");
}
}
public void Increment(int incrementValue) => Interlocked.Add(ref progress, incrementValue);
public void Dispose() => myTimer?.Dispose();
}
This can be called from a parallel method like:
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var myWorkItems = Enumerable.Range(1, 10000).ToList();
using var progress = new MyProgress(TimeSpan.FromSeconds(1), myWorkItems.Count);
DoProcessing(myWorkItems, progress);
}
private static void DoProcessing(IEnumerable<int> items, IMyProgress progress)
{
Parallel.ForEach(items, item =>
{
Thread.Sleep(20);
progress.Increment(1);
});
}
I would be a bit careful when using carriage returns. In my experience console applications tend to be used by other programs as much as by humans, and then it is likely that the output will be redirected to a file, and that does not support carriage returns. So I would try to make the output look good.
I would avoid trying to move the cursor around. I have tried that, but the result was unsatisfactory, YMMV.
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
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");
}
}
}
}