Hello, trying to create an illustration of memory-barriers, in c# - c#

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");
}
}
}
}

Related

Is using two lock statements one after another thread safe?

I've been learning about multi-thread programming and working on the dining philosophers problem. I'm trying to cause a deadlock without sleeping any threads. Here is the code snippet that I'm using:
public class Program
{
const int NumberOfPhilosophers = 5;
const int NumberOfForks = 5;
const int EatingTimeInMs = 20;
static object[] forks = new object[NumberOfForks];
static Thread[] philosopherEatingThreads = new Thread[NumberOfPhilosophers];
public static void Main(string[] args)
{
for (int i = 0; i < NumberOfForks; i++)
{
forks[i] = new object();
}
for (int i = 0; i < NumberOfPhilosophers; i++)
{
int philosopherIndex = i;
philosopherEatingThreads[i] = new Thread(() => { DoWork(philosopherIndex); })
{
Name = philosopherIndex.ToString()
};
philosopherEatingThreads[philosopherIndex].Start();
}
}
public static void DoWork(int philosopherIndex)
{
int fork1Index = philosopherIndex;
int fork2Index = (philosopherIndex + 1 ) % NumberOfForks;
var fork1 = forks[fork1Index];
var fork2 = forks[fork2Index];
lock (fork1)
{
lock (fork2)
{
Thread.Sleep(EatingTimeInMs);
}
}
}
}
I wasn't able to see any deadlocks after trying a couple of times. I know that not experiencing a deadlock does not mean that this code is thread-safe.
For example, when I change the lock statement and add latency I cause deadlock.
lock (fork1)
{
Thread.Sleep(10);
lock (fork2)
{
Thread.Sleep(EatingTimeInMs);
}
}
I have two questions:
Is using two lock statements one after another an atomic operation?
If using Thread.Sleep() causes a deadlock in a code snippet, does that mean that the code snippet is not thread-safe?
Thank you!

BouncyCastle style ThreadedSeeder

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!

Prevent System.StackOverflowException when recursively calling a method

I am new to c# (or coding in general) and I guess this question is really stupid and confusing (I know I'm doing it a hard way) but please help me.
I'm trying to make a minesweeper with form app. I made a 10 x 10 of buttons and if you click it, number of mines around it will be revealed. If a mine is there "F" (the first letter of "False") will appear.
There's a constructor that contains the button, x and y position, list of surrounding blocks, number of mines around it, and a boolean that indicates if there's a mine or not.
What I tried to do was to make the 8 surrounding blocks (from the list) cleared when the player clicked a block with no mine around it and if the block surrounding that block also doesn't have any mine around it, these blocks that surrounding that block will also be cleared. The method uses foreach to reveal and check the number of mines around that block. If there's no mines, same method will be applied to that block (calling the method recursively). The problem is that I keep getting System.StackOverflowException.
I somehow understand why it's happening but I just can't come up with the other way.
//scroll to the bottom for the method with the problem
private void Form1_Load(object sender, EventArgs e)
{
Random random = new Random();
Button[,] buttons = new Button[10, 10]
{
{ r0c0, r0c1, r0c2, r0c3, r0c4, r0c5, r0c6, r0c7, r0c8, r0c9 },
{ r1c0, r1c1, r1c2, r1c3, r1c4, r1c5, r1c6, r1c7, r1c8, r1c9 },
{ r2c0, r2c1, r2c2, r2c3, r2c4, r2c5, r2c6, r2c7, r2c8, r2c9 },
{ r3c0, r3c1, r3c2, r3c3, r3c4, r3c5, r3c6, r3c7, r3c8, r3c9 },
{ r4c0, r4c1, r4c2, r4c3, r4c4, r4c5, r4c6, r4c7, r4c8, r4c9 },
{ r5c0, r5c1, r5c2, r5c3, r5c4, r5c5, r5c6, r5c7, r5c8, r5c9 },
{ r6c0, r6c1, r6c2, r6c3, r6c4, r6c5, r6c6, r6c7, r6c8, r6c9 },
{ r7c0, r7c1, r7c2, r7c3, r7c4, r7c5, r7c6, r7c7, r7c8, r7c9 },
{ r8c0, r8c1, r8c2, r8c3, r8c4, r8c5, r8c6, r8c7, r8c8, r8c9 },
{ r9c0, r9c1, r9c2, r9c3, r9c4, r9c5, r9c6, r9c7, r9c8, r9c9 }
};
Square[,] squares = new Square[10, 10];
for (int i = 0, ii = 0, iii = 0; i < 100; i++, ii++)
{
if (ii == 10)
{
ii = 0;
iii++;
}
squares[ii, iii] = new Square(i, buttons[ii, iii], ii, iii, 0, true);
}
List<int> randoms = new List<int>();
for (int i = 0; i < 10; i++)
{
int ii = random.Next(100);
if (!randoms.Contains(ii))
{
squares[ii % 10, ii / 10].setSafe(false);
}
else
{
i--;
}
randoms.Add(ii);
}
for (int i = 0; i < 10; i++)
{
for (int ii = 0; ii < 10; ii++)
{
for (int iii = -1; iii < 2; iii++)
{
for (int iiii = -1; iiii < 2; iiii++)
{
try
{
if (squares[i + iii, ii + iiii].getSafe() == false)
squares[i, ii].addNumber();
}
catch (System.IndexOutOfRangeException)
{
}
}
//if (squares[i, ii].getSafe() == false) squares[i, ii].getButton().Text = squares[i, ii].getSafe().ToString();
//else squares[i, ii].getButton().Text = squares[i, ii].getNumber().ToString();
}
}
}
for (int i = 0; i < 10; i++)
{
for (int ii = 0; ii < 10; ii++)
{
for (int iii = -1; iii < 2; iii++)
{
for (int iiii = -1; iiii < 2; iiii++)
{
try
{
squares[i, ii].addList(squares[i + iii, ii + iiii]);
}
catch (System.IndexOutOfRangeException)
{
}
}
}
}
}
}
Here's the Square class:
public class Square
{
int id;
Button button;
int x;
int y;
int number;
bool safe;
List<Square> list = new List<Square>();
public Square(int id, Button button, int x, int y, int number, bool safe)
{
this.id = id;
this.button = button;
this.x = x;
this.y = y;
this.number = number;
this.safe = safe;
button.Text = "";
button.Click += button_Click;
}
public int getId()
{
return id;
}
public void setId(int i)
{
id = i;
}
public Button getButton()
{
return button;
}
public void setButton(Button b)
{
button = b;
}
public int getX()
{
return x;
}
public void setX(int i)
{
x = i;
}
public int getY()
{
return y;
}
public void setY(int i)
{
y = i;
}
public int getNumber()
{
return number;
}
public void setNumber(int i)
{
number = i;
}
public void addNumber()
{
number++;
}
public bool getSafe()
{
return safe;
}
public void setSafe(bool b)
{
safe = b;
}
private void button_Click(object sender, EventArgs e)
{
if (getSafe() == false) button.Text = getSafe().ToString();
else button.Text = getNumber().ToString();
if (getNumber() == 0) zeroReveal();
}
//---------------------------------------------------
// this is the method that reveals surrounding blocks
//---------------------------------------------------
private void zeroReveal()
{
foreach (Square s in list)
{
//revealing the blocks
s.getButton().Text = s.getNumber().ToString();
//call the same method if there's no mine
//this is the line that keeps giving me exception
if (s.getNumber() == 0) s.zeroReveal();
}
}
//-----------------------------------------------------
public List<Square> getList()
{
return list;
}
public void setList(List<Square> sl)
{
list = sl;
}
public void addList(Square s)
{
list.Add(s);
}
}
I am new to c# (or coding in general) and I guess this question is really stupid and confusing (I know I'm doing it a hard way)
This topic confuses many a new developer; don't stress out about it!
If there's no mines, same method will be applied to that block (calling the method recursively).
Recursive methods can be confusing but if you design them using the standard pattern, you will avoid SO exceptions. You have not designed yours using the standard pattern.
The standard pattern for successful recursive methods is:
Am I in a case that requires no recursion?
If yes, do the necessary computations to produce the desired effect and return. The problem is now solved.
If no, then we're going to recurse.
Break the current problem down into some number of smaller problems.
Solve each smaller problem by recursing.
Combine the solutions of the smaller problem to solve the current problem.
The problem is now solved, so return.
The most important thing about designing a recursive method is that each recursion must be solving a smaller problem, and the sequence of smaller problems must bottom out at a case that does not require recursion. If those two conditions are not met, then you will get a stack overflow.
Internalize that pattern, and every time you write a recursive method, actually write it out:
int Frob(int blah)
{
if (I am in the base case)
{
solve the base case
return the result
}
else
{
find smaller problems
solve them
combine their solutions
return the result
}
}
Fill in that template with your real code, and you will be much more likely to avoid stack overflows. I've been writing recursive methods for decades, and I still follow this pattern.
Now, in your example, what is the case that does not require recursion? There must be one, so write down what it is. Next, how will you guarantee that the recursion solves a smaller problem? That is often the hard step! Give it some thought.
The stack overflow is occurring because zeroReveal is recursively calling itself forever. To fix this we need to find ways where we do not need it to make further calls to itself.
The name of the method gives us a clue. If the square has already been revealed, then surely the method does not need to do anything, since it has already been revealed.
It looks like the button's Text property is an empty string if it has not yet been revealed. So change the foreach so that it doesn't process squares that have already been revealed:
foreach (Square s in list)
{
if (s.getButton().Text == ""))
{
// existing code in the foreach loop goes here
}
}

How to optimize recursive function for a graph for clearing and settlement

I have to make a module in an Insurance application that deals with clearing and settlement (I think this is the correct financial terminology) between insurance companies enroled in the system. Practically, the system must pair all the amounts that companies have to pay to one another, and only the unpaired (remaining) sums to be paid through the bank. For now there are about 30 companies in the system.
All the readings I did about clearing and settlement pointed me towards graphs and graphs theory (which I have studied in the highschool quite a long time ago).
For a system with 4 companies the graph would look like this:
where each company represents a node (N1 ... N4) and each weighted edge represents the amount that a company has to pay to the other. In my code, the nodes are int, representing the id's of the companies.
What I did so far... I created the graph (for test I used the Random generator for the amounts) and made a recursive function to calculate all posible cycles in the graph. Then I made another recursive function that takes all non-zero cycles starting with the longest path with maximum common sum to pair.
The algorithm seems valid in terms of final results, but for graphs bigger than 7-8 nodes it takes too long to complete. The problem is in the recursive function that creates the possible cycles in the graph. Here is my code:
static void Main(string[] args)
{
int nodes = 4;
try
{
nodes = Convert.ToInt32(args[0]);
}
catch { }
DateTime start = DateTime.Now;
Graph g = new Graph(nodes);
int step = 0;
double CompensatedAmount = 0;
double TotalCompensatedAmount = 0;
DateTime endGeneration = DateTime.Now;
Console.WriteLine("Graph generated in: " + (endGeneration - start).TotalSeconds + " seconds.");
Compensare.RunCompensation(false, g, step, CompensatedAmount, TotalCompensatedAmount, out CompensatedAmount, out TotalCompensatedAmount);
DateTime endCompensation = DateTime.Now;
Console.WriteLine("Graph compensated in: " + (endCompensation - endGeneration).TotalSeconds + " seconds.");
}
... and the main class:
public static class Compensare
{
public static void RunCompensation(bool exit, Graph g, int step, double prevCompensatedAmount, double prevTotalCompensatedAmount, out double CompensatedAmount, out double TotalCompensatedAmount)
{
step++;
CompensatedAmount = prevCompensatedAmount;
TotalCompensatedAmount = prevTotalCompensatedAmount;
if (!exit)
{
List<Cycle> orderedList = g.Cycles.OrderByDescending(x => x.CycleCompensatedAmount).ToList();
g.ListCycles(orderedList, "OrderedCycles" + step.ToString() + ".txt");
using (Graph clona = g.Clone())
{
int maxCycleIndex = clona.GetMaxCycleByCompensatedAmount();
double tmpCompensatedAmount = clona.Cycles[maxCycleIndex].CycleMin;
exit = tmpCompensatedAmount <= 0 ? true : false;
CompensatedAmount += tmpCompensatedAmount;
TotalCompensatedAmount += (tmpCompensatedAmount * clona.Cycles[maxCycleIndex].EdgesCount);
clona.CompensateCycle(maxCycleIndex);
clona.UpdateCycles();
Console.WriteLine(String.Format("{0} - edges: {4} - min: {3} - {1} - {2}\r\n", step, CompensatedAmount, TotalCompensatedAmount, tmpCompensatedAmount, clona.Cycles[maxCycleIndex].EdgesCount));
RunCompensation(exit, clona, step, CompensatedAmount, TotalCompensatedAmount, out CompensatedAmount, out TotalCompensatedAmount);
}
}
}
}
public class Edge
{
public int Start { get; set; }
public int End { get; set; }
public double Weight { get; set; }
public double InitialWeight {get;set;}
public Edge() { }
public Edge(int _start, int _end, double _weight)
{
this.Start = _start;
this.End = _end;
this.Weight = _weight;
this.InitialWeight = _weight;
}
}
public class Cycle
{
public List<Edge> Edges = new List<Edge>();
public double CycleWeight = 0;
public double CycleMin = 0;
public double CycleMax = 0;
public double CycleAverage = 0;
public double CycleCompensatedAmount = 0;
public int EdgesCount = 0;
public Cycle() { }
public Cycle(List<Edge> _edges)
{
this.Edges = new List<Edge>(_edges);
UpdateCycle();
}
public void UpdateCycle()
{
UpdateCycle(this);
}
public void UpdateCycle(Cycle c)
{
double sum = 0;
double min = c.Edges[0].Weight;
double max = c.Edges[0].Weight;
for(int i=0;i<c.Edges.Count;i++)
{
sum += c.Edges[i].Weight;
min = c.Edges[i].Weight < min ? c.Edges[i].Weight : min;
max = c.Edges[i].Weight > max ? c.Edges[i].Weight : max;
}
c.EdgesCount = c.Edges.Count;
c.CycleWeight = sum;
c.CycleMin = min;
c.CycleMax = max;
c.CycleAverage = sum / c.EdgesCount;
c.CycleCompensatedAmount = min * c.EdgesCount;
}
}
public class Graph : IDisposable
{
public List<int> Nodes = new List<int>();
public List<Edge> Edges = new List<Edge>();
public List<Cycle> Cycles = new List<Cycle>();
public int NodesCount { get; set; }
public Graph() { }
public Graph(int _nodes)
{
this.NodesCount = _nodes;
GenerateNodes();
GenerateEdges();
GenerateCycles();
}
private int FindNode(string _node)
{
for(int i = 0; i < this.Nodes.Count; i++)
{
if (this.Nodes[i].ToString() == _node)
return i;
}
return 0;
}
private int FindEdge(string[] _edge)
{
for(int i = 0; i < this.Edges.Count; i++)
{
if (this.Edges[i].Start.ToString() == _edge[0] && this.Edges[i].End.ToString() == _edge[1] && Convert.ToDouble(this.Edges[i].Weight) == Convert.ToDouble(_edge[2]))
return i;
}
return 0;
}
public Graph Clone()
{
Graph clona = new Graph();
clona.Nodes = new List<int>(this.Nodes);
clona.Edges = new List<Edge>(this.Edges);
clona.Cycles = new List<Cycle>(this.Cycles);
clona.NodesCount = this.NodesCount;
return clona;
}
public void CompensateCycle(int cycleIndex)
{
for(int i = 0; i < this.Cycles[cycleIndex].Edges.Count; i++)
{
this.Cycles[cycleIndex].Edges[i].Weight -= this.Cycles[cycleIndex].CycleMin;
}
}
public int GetMaxCycleByCompensatedAmount()
{
int toReturn = 0;
for (int i = 0; i < this.Cycles.Count; i++)
{
if (this.Cycles[i].CycleCompensatedAmount > this.Cycles[toReturn].CycleCompensatedAmount)
{
toReturn = i;
}
}
return toReturn;
}
public void GenerateNodes()
{
for (int i = 0; i < this.NodesCount; i++)
{
this.Nodes.Add(i + 1);
}
}
public void GenerateEdges()
{
Random r = new Random();
for(int i = 0; i < this.Nodes.Count; i++)
{
for(int j = 0; j < this.Nodes.Count; j++)
{
if(this.Nodes[i] != this.Nodes[j])
{
int _weight = r.Next(0, 500);
Edge e = new Edge(this.Nodes[i], this.Nodes[j], _weight);
this.Edges.Add(e);
}
}
}
}
public void GenerateCycles()
{
for(int i = 0; i < this.Edges.Count; i++)
{
FindCycles(new Cycle(new List<Edge>() { this.Edges[i] }));
}
this.UpdateCycles();
}
public void UpdateCycles()
{
for (int i = 0; i < this.Cycles.Count; i++)
{
this.Cycles[i].UpdateCycle();
}
}
private void FindCycles(Cycle path)
{
List<Edge> nextPossibleEdges = GetNextEdges(path.Edges[path.Edges.Count - 1].End);
for (int i = 0; i < nextPossibleEdges.Count; i++)
{
if (path.Edges.IndexOf(nextPossibleEdges[i]) < 0) // the edge shouldn't be already in the path
{
Cycle temporaryPath = new Cycle(path.Edges);
temporaryPath.Edges.Add(nextPossibleEdges[i]);
if (nextPossibleEdges[i].End == temporaryPath.Edges[0].Start) // end of path - valid cycle
{
if (!CycleExists(temporaryPath))
{
this.Cycles.Add(temporaryPath);
break;
}
}
else
{
FindCycles(temporaryPath);
}
}
}
}
private bool CycleExists(Cycle cycle)
{
bool toReturn = false;
if (this.Cycles.IndexOf(cycle) > -1) { toReturn = true; }
else
{
for (int i = 0; i < this.Cycles.Count; i++)
{
if (this.Cycles[i].Edges.Count == cycle.Edges.Count && !CompareEdges(this.Cycles[i].Edges[0], cycle.Edges[0]))
{
bool cycleExists = true;
for (int j = 0; j < cycle.Edges.Count; j++)
{
bool edgeExists = false; // if there is an edge not in the path, then the searched cycle is diferent from the current cycle and we can pas to the next iteration
for (int k = 0; k < this.Cycles[i].Edges.Count; k++)
{
if (CompareEdges(cycle.Edges[j], this.Cycles[i].Edges[k]))
{
edgeExists = true;
break;
}
}
if (!edgeExists)
{
cycleExists = false;
break;
}
}
if (cycleExists) // if we found an cycle with all edges equal to the searched cycle, then the cycle is not valid
{
toReturn = true;
break;
}
}
}
}
return toReturn;
}
private bool CompareEdges(Edge e1, Edge e2)
{
return (e1.Start == e2.Start && e1.End == e2.End && e1.Weight == e2.Weight);
}
private List<Edge> GetNextEdges(int endNode)
{
List<Edge> tmp = new List<Edge>();
for(int i = 0; i < this.Edges.Count; i++)
{
if(endNode == this.Edges[i].Start)
{
tmp.Add(this.Edges[i]);
}
}
return tmp;
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: dispose managed state (managed objects).
this.Nodes = null;
this.Edges = null;
this.Cycles = null;
this.NodesCount = 0;
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~Graph() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
#endregion
}
I've found several articles/answers about graphs, both in Java and C# (including quickgraph), but they mainly focus on directed graphs (without cycles).
I have also read about tail call optimization, for recursion, but I don't know if/how to implement in my case.
I now there is a lot to grasp about this subject, but maybe someone had to deal with something similar and can either help me optimize the code (which as I said seems to do the job in the end), either point me to another direction to rethink the whole process.
I think you can massively simplify this.
All money is the same, so (using your example) N1 doesn't care whether it gets 350 from N2 and pays 150 to N2 and so on - N1 merely cares that overall it ends up 145 down (if I've done the arithmetic correctly). Similarly, each other N only cares about its overall position. So, summing the inflows and outflows at each node, we get:
Company Net position
N1 -145
N2 -65
N3 +195
N4 +15
So with someone to act as a central clearing house - the bank - simply arrange for N1 and N2 to pay the clearing house 145 and 65 respectively, and for N3 and N4 to receive 195 and 15 respectively from the clearing house. And everyone's happy.
I may have missed some aspect, of course, in which case I'm sure someone will point it out...

Weird issue in Console app

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. :)

Categories