(Background) I am creating a stock market emulation program to further my C# knowledge. I previously created this program in Java.
(Issue) In Java, I was able to create a new thread in order to have it loop and update my GUI's labels every x amount of time. I researched methods to do this in C# and came across the timer, this didn't work for me and so I resorted to multi-threading.
Upon startup of the form I create a new thread
/// <summary>
/// stock emulation startup
/// </summary>
public stockEmu()
{
CheckForIllegalCrossThreadCalls = false; //if this is true, then cross-thread changes cannot be made (repeater cannot set labels if true)
initializeValues(); //this will set the startup values e.g stock prices and user money
ThreadStart loopThread = new ThreadStart( repeater ); //opens a new thread
Thread openThread = new Thread( loopThread ); //opens a new thread
openThread.Start(); //opens a new thread
InitializeComponent(); //initializes the form
this.updateLabels(); //needs to be after initializecomponent or null exception is thrown (because the labels are not drawn yet)
}
Here is the new thread method:
/// <summary>
/// infinite loop to execute every x seconds (using a new thread)
/// repeater uses cross-thread operation(s) and so CheckForIllegalCrossThreadCalls has been set to false
/// MSDN recommends against this, it is executed safely however
/// </summary>
private void repeater()
{
while( true )
{
Thread.Sleep( 5000 ); //sleep (pause) the thread for 5 seconds
instance = instance + 1; //add to the current instance (this is used to display what "day" we're on
changePrices(); //change the prices of the stocks
updateLabels(); //update the form's labels to display the new values
}
}
Here are the methods the repeater calls every 5 seconds
/// <summary>
/// this will change the prices every x seconds based on current prices etc
/// </summary>
private void changePrices()
{
marketController mC = new marketController();
for( int i = 0 ; i < stocks.Length ; i++ )
{
mC.changePrices( stocks [ i ] , i ); //mc for marketController, object reference, change prices will calc the price changes
}
return;
}
mC.changePrices doesn't actually do anything yet, but it does not get stuck there.
/// <summary>
/// method used to update all display labels every x seconds (based on repeater)
/// </summary>
public void updateLabels()
{
try
{
this.userMoneyLabel.Text = "Your money: " + this.getUserMoney().ToString(); //changes the user's money label
this.currentDayLabel.Text = "Day: " + this.getInstance().ToString(); //changes the day label
this.setStocksCombined(); //sets the array of combined stock prices and stock names
this.stockListBox.Items.Clear(); //clear the list box because it will constantly stack the items
this.stockListBox.Items.AddRange( stocksCombined ); //adds the combined array to the list box (stocks + stockNames)
}
catch( Exception e )
{
MessageBox.Show( "Error: " + e );
}
}
All of the relevant labels update fine, this problem also persisted before I added setStocksCombined() and so I don't believe the problem lies there.
This is the error that is thrown:
An unhandled exception of type 'System.OutOfMemoryException' occurred in mscorlib.dll
I haven't opened any additional threads apart from repeater, the repeater normally throws this error when it reached instance 7.
Thanks in advance (hopefully)
Edit:
Thanks to @RichardSzalay and @MichaelThePotato I have implemented a timer using this example: https://stackoverflow.com/a/12535833/6639187
MSDN recommends against this, it is executed safely howeverseems like a weird assumption given that the application crashes. Not saying it is causing it but it might be.Taskto do your background work. Creating threads directly in .net in 2016 is essentially unheard of, and always eyebrow-raise worthy. Tasks, on the other hand, are par for the course.