I have a library that returns CS:GO stats in real-time from the game. I'm making a program that stores the stats and analyse it.
I have this function:
private void UpdateKills(GameState gs)
{
int currentKills = -1;
if (lastKills == -1) // first time getting player info
{
int temp = gs.Player.MatchStats.Kills;
currentKills = temp;
lastKills = temp;
}
else
{
currentKills = gs.Player.MatchStats.Kills;
int dif = currentKills - lastKills;
if (currentKills == 0 && lastKills != 0) // maybe changed server/map/whatever
{
lastKills = -1;
}
else
{
if (dif != 0 && dif > 0) // player killed someone AND it was not teamkill
{
ps.Kills += dif; // add the kills to the main variable
lastKills = currentKills;
dif = 0;
playSimpleSound();
}
}
}
}
This is my function that handles the kills. The most of the time it works very well, but sometimes it just freaks out, and I don't know if the problem is my logic or if it is a library problem.
Note: I'm using this library: github.com/rakijah/CSGSI
My logic is:
Get the player kills
Increment those kills in the PlayerStats object.
Is my code logically correct? Can my code be more "correct"?
I'm still not entirely sure what this function is supposed to be doing, but I simplified it for you:
private void UpdateKills(GameState gs)
{
lastKills = currentKills;
int currentKills = gs.Player.MatchStats.Kills;
int diff = currentKills - lastKills;
if (currentKills == 0 && lastKills != 0) // maybe changed server/map/whatever
{
lastKills = -1;
}
else if (diff > 0) // player killed someone AND it was not teamkill
{
ps.Kills += diff; // add the kills to the main variable
playSimpleSound();
}
}
Well, after some research in finally undertand your problem. You DON'T have to do anything!, the API does all the work for you, watch the next image:
As you can see, the console app shows my steam name, the map and kills. I start with zero kills, then I kill a teammate and after that an enemy. The API created by #rakijah autoupdates those values.
Now the code:
static void Main(string[] args)
{
CsGoIntegration();
}
private static void CsGoIntegration()
{
var gsl = new GameStateListener(3000);
gsl.NewGameState += new NewGameStateHandler(OnNewGameState);
if (!gsl.Start())
{
Environment.Exit(0);
}
System.Console.WriteLine("Listening...");
}
private static void OnNewGameState(GameState gs)
{
System.Console.WriteLine("Map: {0}", gs.Map.Name);
System.Console.WriteLine("Player Name: {0}", gs.Player.Name);
System.Console.WriteLine("Player Kills: {0}", gs.Player.MatchStats.Kills);
}
UPDATE: The OP needs to store the total kills even when the map changes. I experimented with paper and pencil, please try running the program and tell me if it worked or not
private static void Main()
{
CsGoIntegration();
}
private static void CsGoIntegration()
{
var gsl = new GameStateListener(3000);
gsl.NewGameState += OnNewGameState;
if (!gsl.Start())
{
Environment.Exit(0);
}
Console.WriteLine("Listening...");
}
private static void OnNewGameState(GameState gameState)
{
SaveMatchsData(gameState);
}
private static int? _totalKillScore;
private static string _lastMapName;
private static int? _lastKillScore;
private static void SaveMatchsData(GameState gameState)
{
const string undefinedString = "Undefined";
// If the SaveMatchsData is running and the CSGO server is offline
if (gameState.Map.Name == undefinedString && string.IsNullOrEmpty(_lastMapName))
return;
// When the match is not started, the Round is -1
if (gameState.Map.Name != undefinedString && gameState.Map.Round > -1)
{
if (string.IsNullOrEmpty(_lastMapName))
{
UpdateData(gameState, true);
}
else
{
// Same map
if (_lastMapName == gameState.Map.Name)
{
// Check if the Score Changes
if (_lastKillScore == gameState.Player.MatchStats.Kills) return;
UpdateData(gameState);
}
// The Map Changes
else
{
UpdateData(gameState, true);
}
}
}
}
private static void UpdateData(GameState gameState, bool updateMap = false)
{
if (updateMap)
_lastMapName = gameState.Map.Name;
_lastKillScore = gameState.Player.MatchStats.Kills;
_totalKillScore += gameState.Player.MatchStats.Kills;
}
Cheers.
Related
Iterating through an array of strings i want it to write a specific line if one of the elements coresponds to the condition. The problem is with the else condition. It is written as many times as the length of the array and i only need it written once
public static void FindSandy(params string[] ocean)
{
for (int i = 0; i < ocean.Length; i++)
{
if (ocean[i] == "Sandy")
{
Console.WriteLine("We found Sandy on position {0}", i);
}
else
{
Console.WriteLine("He was not here");
}
}
}
static void Main(string[] args)
{
{
FindSandy("Bob","Bella", "Sandy", "Nemo", "Dory");
}
}
What about if you just return if you found it?
public static void FindSandy(params string[] ocean)
{
for (int i = 0; i < ocean.Length; i++)
{
if (ocean[i] == "Sandy")
{
Console.WriteLine("We found Sandy on position {0}", i);
// Found, you can return from method.
return;
}
}
// Not found, write the 'not found' message.
Console.WriteLine("He was not here");
}
The simplest way to change your code to handle this is to create a variable that tracks the index where Sandy is found, initialize it to an invalid value (like -1), and then set it to the actual value in your if block (and we can also add a break; statement to exit the loop as soon as we find him).
Then, we output a string based on the value of the position variable:
public static void FindSandy(params string[] ocean)
{
int position = -1;
for (int i = 0; i < ocean?.Length; i++)
{
if (ocean[i] == "Sandy")
{
position = i;
break;
}
}
if (position > -1)
{
Console.WriteLine("We found Sandy on position {0}", position);
}
else
{
Console.WriteLine("He was not here");
}
}
The code can be simplified a little with the System.Linq extension methods Select (to select the name and then index) and FirstOrDefault which returns the first item that meets a condidion, or the default for the type (which is null):
public static void FindSandy(params string[] ocean)
{
var position = ocean?.Select((name, index) => new {name, index})
.FirstOrDefault(item => item.name == "Sandy");
Console.WriteLine(position == null
? "He was not here"
: $"We found Sandy on position {position.index}");
}
You can use the keyword break to exit the for loop :
public static void FindSandy(params string[] ocean)
{
for (int i = 0; i < ocean.Length; i++)
{
if (ocean[i] == "Sandy")
{
Console.WriteLine("We found Sandy on position {0}", i);
break;
}
else if (i == ocean.Length - 1)
{
Console.WriteLine("He was not here");
break;
}
}
}
To solve your issue, you could add a new boolean variable (e.g. weFoundSandy): if you find an occurrence, set this variable to true, use the break statement (to reduce the iterations of the for) and, at the end, use this boolean variable to determine which message to display.
public static void FindSandy(params string[] ocean) {
bool weFoundSandy = false;
for (int i = 0; i < ocean.Length; i++) {
if (ocean[i] == "Sandy") {
Console.WriteLine("We found Sandy on position {0}", i);
weFoundSandy = true;
break;
}
}
if (!weFoundSandy) {
Console.WriteLine("Sandy was not here");
}
}
or, you could simply use the C# Array.IndexOf method, e.g.:
public static void FindSandy(params string[] ocean) {
int indexOfSandy = Array.IndexOf(ocean, "Sandy");
if (indexOfSandy >= 0) {
Console.WriteLine("We found Sandy on position {0}", indexOfSandy);
} else {
Console.WriteLine("Sandy was not here");
}
}
I have created code for a question generator but every now and then my random.range is picking two of my gameobjects(out of 20). The code should work but something is causing it to pick two. Is it a bug with unity or the code itself? I have created a list and then when the number is picked it should the delete it from the list preventing any number duplication's(same question asked twice).
public GameObject Question1, Question2, Question3, Question4, Question5, Question6, Question7, Question8, Question9, Question10, Question11, Question12, Question13, Question14, Question15, Question16, Question17, Question18, Question19, Question20;
public GameObject VerdictGood, VerdictBad;
public GameObject box_QA;
public courtDialogue _courtDialogue;
List<int> list = new List<int>();
private int i, index, calculate, maxquestions;
public bool neverdone;
public void Start()
{
box_QA.SetActive(false);
calculate = 0;
for (int n = 1; n < 21; n++)
{
list.Add(n);
}
}
void Update()
{
DeleteQuestions();
}
public void CheckQuestion()
{
index = Random.Range(0, list.Count - 1);
i = list[index];
Debug.Log(i);
list.RemoveAt(index);
}
public void WhatQuestion()
{
CheckQuestion();
if (i == 1)
{
Question1.SetActive(true);
Question2.SetActive(false);
Question3.SetActive(false);
Question4.SetActive(false);
Question5.SetActive(false);
Question6.SetActive(false);
Question7.SetActive(false);
Question8.SetActive(false);
Question9.SetActive(false);
Question10.SetActive(false);
Question11.SetActive(false);
Question12.SetActive(false);
Question13.SetActive(false);
Question14.SetActive(false);
Question15.SetActive(false);
Question16.SetActive(false);
Question17.SetActive(false);
Question18.SetActive(false);
Question19.SetActive(false);
Question20.SetActive(false);
}
}
void DeleteQuestions()
{
if (maxquestions == 10)
{
StopCoroutine("CheckQuestion");
StopCoroutine("WhatQuestion");
Destroy(Question1);
Destroy(Question2);
Destroy(Question3);
Destroy(Question4);
Destroy(Question5);
Destroy(Question6);
Destroy(Question7);
Destroy(Question8);
Destroy(Question9);
Destroy(Question10);
Destroy(Question11);
Destroy(Question12);
Destroy(Question13);
Destroy(Question14);
Destroy(Question15);
Destroy(Question16);
Destroy(Question17);
Destroy(Question18);
Destroy(Question19);
Destroy(Question20);
if (calculate > 7)
{
JudgeImage.GetComponent<Image>().color = new Color32(6, 255, 0, 255);
VerdictGood.SetActive(true);
Debug.Log("Not Quilty");
}
else
{
JudgeImage.GetComponent<Image>().color = new Color32(255, 0, 0, 255);
VerdictBad.SetActive(true);
Debug.Log("Not Quilty");
}
}
}
Console Output
public GameObject judgeFace;
public GameObject prosecutorFace;
public GameObject clientFace;
public GameObject courtQuestions;
public GameObject healthBar;
public int courtIntroCount; //This variable keeps track of whose line is next in the court dialogue scene.
public GameObject fullTextBox;
public Text nameText;
public Text mainText;
public float delay = 0.1f;
public string fullText;
private string currentText = "";
public GameManager2 _gameManager2;
// Use this for initialization
void Start ()
{
// courtQuestions.SetActive(false);
fullTextBox.SetActive(false);
healthBar.SetActive(false);
Invoke("CourtIntro1", 3);
}
IEnumerator ShowText()
{
for (int i = 0; i < fullText.Length; i++)
{
currentText = fullText.Substring(0, i);
mainText.GetComponent<Text>().text = currentText;
yield return new WaitForSeconds(delay);
}
}
// Update is called once per frame
public void CourtButtons()
{
if (courtIntroCount == 1)
CourtIntro2();
else if (courtIntroCount == 2)
CourtIntro3();
else if(courtIntroCount == 3)
CourtIntro4();
else if(courtIntroCount == 4)
CourtIntro5();
else if (courtIntroCount == 5)
CourtIntroEND();
// This needs to have a way of checking which question has been disabled after the answer has been selected
}
// COURT DIALOGUE _ INTRO SEQUENCE
public void CourtIntro1()
{
courtIntroCount = 1;
fullTextBox.SetActive(true);
judgeFace.SetActive(true);
nameText.text = "Judge";
StartCoroutine(ShowText());
currentText = "Court is now in-session. All rise.";
}
public void CourtIntro2()
{
courtIntroCount = 2;
fullTextBox.SetActive(true);
nameText.text = "Judge";
StartCoroutine(ShowText());
fullText = "Now, you, lawyer. Do you solemnly and sincerely and truly declare and affirm that the evidence you shall give shall be the truth, the whole truth and nothing but the truth?.";
}
public void CourtIntro3()
{
courtIntroCount = 3;
fullTextBox.SetActive(true);
nameText.text = "Judge";
StartCoroutine(ShowText());
fullText = "... Very good. Now, the prosecution would like to begin by asking the defence a number of questions..";
}
public void CourtIntro4()
{
courtIntroCount = 4;
fullTextBox.SetActive(true);
judgeFace.SetActive(false);
prosecutorFace.SetActive(true);
nameText.text = "Prosecutor";
StartCoroutine(ShowText());
fullText = "I would, Your Honour. I hope the defence will be able to answer them accurately and appropriately for you and the jury..";
}
public void CourtIntro5()
{
courtIntroCount = 5;
fullTextBox.SetActive(true);
prosecutorFace.SetActive(false);
clientFace.SetActive(true);
nameText.text = "Ellen";
StartCoroutine(ShowText());
fullText = "This is it! You'll need to convince the judge and jury that I'm not guilty. Best of luck!.";
}
public void CourtIntroEND()
{
courtIntroCount = 10;
clientFace.SetActive(false);
fullTextBox.SetActive(false);
//courtQuestions.SetActive(true);
healthBar.SetActive(true);
_gameManager2.box_QA.SetActive(true);
_gameManager2.WhatQuestion();
}
It would be nice to have more information about how this is structured, but based on what I see here, it looks like your WhatQuestion() method needs to know what the variable 'i' is. This is usually done by creating methods that accept parameters and return values. For this example, it looks like your CheckQuestion() method should return a value of 'i':
public int CheckQuestion()
{
//do some stuff
return i;
}
Then, your WhatQuestion() method should call CheckQuestion() to get 'i':
public void WhatQuestion()
{
i = CheckQuestion();
if (i == 1)
{
//Do your stuff
}
}
You may also need a way to de-activate all of the other questions so that only one is activated at a time. Something like
foreach (var question in QuestionList)
{
question.SetActive(false);
}
Then, to activate the one question:
QuestionList[i].SetActive(true);
Hope this info helps, it's my best guess with what's presented here.
I'm trying to make 'find/find next' function in my windows store application.
Word which I want to search and select is in textBox named 'tboxFind'.
Textbox 'EditorWindow' contains all my text.
My function works good only if there is one line of text in 'editorWindow'.
Otherwise, selection is moved forwards by number of new lines.
How to fix it?
Is there any simple way to create find next function?
private void btnFind_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
if ((tmpPos) == pos && tmpWord == tboxFind.Text && !String.IsNullOrEmpty(editorWindow.Text))
{
string tmpString = editorWindow.Text.Substring(pos + tboxFind.Text.Length);
tmpPos = tmpString.ToLower().IndexOf(tboxFind.Text.ToLower());
if (tmpPos != -1)
{
editorWindow.Focus(Windows.UI.Xaml.FocusState.Keyboard);
editorWindow.SelectionStart = pos + tmpPos + tboxFind.Text.Length;
editorWindow.SelectionLength = tboxFind.Text.Length;
pos = pos + tmpPos + tboxFind.Text.Length;
}
}
tmpWord = tboxFind.Text;
tmpPos = pos;
}
// EDIT:
I found a different way to create that function. Here is my code:
private void btnFind_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
numOfNewLines = 0;
pos = (tmpWord == tboxFind.Text) ? editorWindow.Text.ToLower().IndexOf(tboxFind.Text, pos + tboxFind.Text.Length)
: editorWindow.Text.ToLower().IndexOf(tboxFind.Text);
if (pos != -1)
{
foreach (char s in editorWindow.Text.Substring(0, pos))
{
if (s == '\n')
{
numOfNewLines++;
}
}
pos -= numOfNewLines;
editorWindow.Focus(Windows.UI.Xaml.FocusState.Keyboard);
//tmpPos = editorWindow.Text.ToLower().IndexOf(tboxFind.Text);
editorWindow.Select(pos, tboxFind.Text.Length);
pos += numOfNewLines;
}
tmpWord = tboxFind.Text;
}
I'm not 100% sure what's wrong with your code because I can't fully replicate it, but consider the following SSCCE in a basic Windows application:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
foreach (var i in FindIndicies("text"))
{
this.textBox1.SelectionStart = i;
this.textBox1.SelectionLength = "text".Length;
var result = MessageBox.Show(
"Move to the next index?",
"Next?",
MessageBoxButtons.YesNo);
if (result == System.Windows.Forms.DialogResult.No) { break; }
}
}
private List<int> FindIndicies(string textToFind)
{
var indicies = new List<int>();
var offset = 0;
var i = 0;
while ((i = this.textBox1.Text.IndexOf(
textToFind,
offset,
StringComparison.CurrentCultureIgnoreCase)) > 0)
{
indicies.Add(i);
offset = (i + textToFind.Length);
}
return indicies;
}
}
given that textBox1 has a set text value of:
Here is a set of text
and I'm going to find the word text
Even when there are multiple lines of text.
It finds each index properly, and selects them properly.
I would consider finding all indicies up front with the method I wrote and then simply iterate through them on demand. In my case I'm using a message box to determine when I want to move to the next index, but you'll use something different.
Ive got this problem:
Line 20 (LOOT_FromContainer(container) I need that to use as Invoke, because the process I want to exec takes some time, so ServerMessageHandler won't handle it...
If I just simply rewrite that line to LOOT_FromContainer.BeginInvoke(container); then I have this error:
error CS0119: 'LOOT.LOOT_FromContainer(Phoenix.Serial)' is a 'method',
which is not valid in the given context
I'm new to C#, came from PHP, and about Invoke I don't know much really. I've been trying to sort this out for a couple of days, not even google helped...
[ServerMessageHandler(0x3C)]
public CallbackResult ContainerContains(byte[] data, CallbackResult prevResult)
{
PacketReader reader = new PacketReader(data);
reader.Skip(3);
ushort len = reader.ReadUInt16();
for (int i = 0; i < len; i++)
{
Serial serial = (Serial)(reader.ReadUInt32());
ushort graphic = (ushort)(reader.ReadUInt16());
reader.Skip(7);
Serial container = (Serial)(reader.ReadUInt32());
ushort color = (ushort)(reader.ReadUInt16());
if (((int)graphic == 0x0E76) && ((int)color == 0x049A))
{
LOOT_FromContainer.BeginInvoke(container);
}
}
return CallbackResult.Normal;
}
[Command]
public static void LOOT_FromContainer(Serial target)
{
UOItem lootCorpse = new UOItem(target);
if (lootCorpse.Graphic == 0x2006)
{
if (((draw == 1) && (World.Player.Backpack.AllItems.Count(draw_knife[0], draw_knife[1]) > 0)) || (World.Player.Layers[Layer.RightHand].Exist))
{
if ((lootCorpse.Amount != 400) && (lootCorpse.Amount != 401))
{
if (draw == 0)
{
UO.WaitTargetObject(lootCorpse);
UO.UseObject(World.Player.Layers[Layer.RightHand].Serial);
}
else
{
UO.WaitTargetObject(lootCorpse);
UO.UseType(draw_knife[0], draw_knife[1]);
}
UO.Wait(500);
}
}
else
{
UO.Print("Neni cim rezat, pouze lootim");
}
for (int i = 0; i < loot.Length; i++)
{
if (lootCorpse.Items.Count(loot[i][0], loot[i][1]) > 0)
{
if (loot[i][2] == 1)
{
if (loot[i][4] == 1)
{
UO.MoveItem(lootCorpse.Items.FindType(loot[i][0], loot[i][1]), 0, Aliases.GetObject("loot_bag"), loot[i][5], loot[i][6]);
UO.Wait(200);
}
else
{
UO.MoveItem(lootCorpse.Items.FindType(loot[i][0], loot[i][1]), 0, World.Player.Backpack);
UO.Wait(200);
}
}
}
}
}
}
I think this is what you need. You need to declare a delegate with the same return type and input parameters as your method, instantiate this delegate pointing it at your method and then call BeginInvoke on it passing in your serial variable, followed by null, null:
public delegate void LFC(Serial target);
[ServerMessageHandler(0x3C)]
public CallbackResult ContainerContains(byte[] data, CallbackResult prevResult)
{
PacketReader reader = new PacketReader(data);
reader.Skip(3);
ushort len = reader.ReadUInt16();
for (int i = 0; i < len; i++)
{
Serial serial = (Serial)(reader.ReadUInt32());
ushort graphic = (ushort)(reader.ReadUInt16());
reader.Skip(7);
Serial container = (Serial)(reader.ReadUInt32());
ushort color = (ushort)(reader.ReadUInt16());
LFC = lootfromcontainer = new LFC(LOOT_FromContainer);
if (((int)graphic == 0x0E76) && ((int)color == 0x049A))
{
lootfromcontainer.BeginInvoke(container, null, null);
//LOOT_FromContainer.BeginInvoke(container);
}
}
return CallbackResult.Normal;
}
[Command]
public static void LOOT_FromContainer(Serial target)
{
UOItem lootCorpse = new UOItem(target);
if (lootCorpse.Graphic == 0x2006)
{
if (((draw == 1) && (World.Player.Backpack.AllItems.Count(draw_knife[0], draw_knife[1]) > 0)) || (World.Player.Layers[Layer.RightHand].Exist))
{
if ((lootCorpse.Amount != 400) && (lootCorpse.Amount != 401))
{
if (draw == 0)
{
UO.WaitTargetObject(lootCorpse);
UO.UseObject(World.Player.Layers[Layer.RightHand].Serial);
}
else
{
UO.WaitTargetObject(lootCorpse);
UO.UseType(draw_knife[0], draw_knife[1]);
}
UO.Wait(500);
}
}
else
{
UO.Print("Neni cim rezat, pouze lootim");
}
for (int i = 0; i < loot.Length; i++)
{
if (lootCorpse.Items.Count(loot[i][0], loot[i][1]) > 0)
{
if (loot[i][2] == 1)
{
if (loot[i][4] == 1)
{
UO.MoveItem(lootCorpse.Items.FindType(loot[i][0], loot[i][1]), 0, Aliases.GetObject("loot_bag"), loot[i][5], loot[i][6]);
UO.Wait(200);
}
else
{
UO.MoveItem(lootCorpse.Items.FindType(loot[i][0], loot[i][1]), 0, World.Player.Backpack);
UO.Wait(200);
}
}
}
}
}
}
If you simply need to run that in another thread you can use ThreadPool.
For this you would need few easy things:
Instead of:
LOOT_FromContainer.BeginInvoke(container);
You would use:
ThreadPool.QueueUserWorkItem(LOOT_FromContainer, container);
And slightly modify your LOOT_FromContainer method to:
public static void LOOT_FromContainer(object prm)
{
var target = (Serial)prm;
// ...
I'm assuming LOOT_FromCotainer is a control, and given the error your compiler returns, one can roughly guess the problem is that you're calling BeginInvoke with a non-delegate. BeginInvoke is called as follows:
LOOT_FromContainer.BeginInvoke(container); //where container is a delegate that maybe declared as follows
private delegate void container; //may also contain parameters eg container(string s);
So just rework your code to follow in this manner. See this document for example on how to use BeginInvoke.
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");
}
}
}
}