Accessing RichTextBox in Multi-threaded application causes OutOfMemoryException - c#

I am probably just doing it very wrong. I am currently working with MSMQ and Webservices. I wanted to learn how MSMQ worked so I found a school example of a Loan Broker.
To make a long story short, I need to be able to stress test my system, so I want to be able to make, say, 100 messages and send them through my messaging system. I want to do that from a Windows Form application, but here lies the problem. I have a form that looks like this:
On the left you see a custom control and on the right, my "console" window that tells me what's going on. When I press the Send button, it should use the data given in the fields above it, to send messages. But when I press the Send Button, the program freezes for a while and then hits the OutOfMemoryException. This is the Send method:
private void Send(List<SimpleRequest.LoanRequest> list)
{
int quantity = int.Parse(numericQuantity.Value.ToString());
int delay = int.Parse(numericDelay.Value.ToString());
if (list.Count == 1)
{
for (int threadnumber = 0; threadnumber < quantity; threadnumber++)
{
Task.Factory.StartNew(() => RequestLoanQuote(threadnumber, list[0]));
if (delay > 0)
{
Thread.Sleep(delay);
}
}
}
else
{
for (int threadnumber = 0; threadnumber < quantity; threadnumber++)
{
Task.Factory.StartNew(() => RequestLoanQuote(threadnumber, list[threadnumber]));
if (delay > 0)
{
Thread.Sleep(delay);
}
}
}
}
Here is the RequestLoanQuote method that the Send method is calling:
private void RequestLoanQuote(object state, SimpleRequest.LoanRequest loanRequest)
{
try
{
if (console.InvokeRequired)
{
SetText("Sending: " + loanRequest.SSN + "\n");
}
StringBuilder sb = new StringBuilder();
var threadnumber = (int)state;
using (var client = new LoanBrokerWS.LoanBrokerWSClient())
{
Utility_Tool.LoanBrokerWS.LoanQuote response = client.GetLoanQuote(loanRequest.SSN, loanRequest.LoanAmount, loanRequest.LoanDuration);
sb.Append(response.SSNk__BackingField + " returned: ");
sb.Append(response.interestRatek__BackingField + " | ");
sb.Append(response.BankNamek__BackingField + "\n");
SetText(sb.ToString());
}
}
catch (Exception e)
{
SetText(e.Message + "\n");
}
}
And finally, the SetText method:
private void SetText(String msg)
{
if (this.console.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { msg });
}
else
{
this.console.Text += msg;
}
}
So the Send method calls the RequestLoanQuote method which calls the SetText method. I cannot figure out where I went wrong but it's probably a deadlock.

Try using BeginInvoke and AppendText, like so:
public static void SetText(this RichTextBox textBox, string msg)
{
Action append = () => textBox.AppendText(msg);
if (textBox.InvokeRequired)
textBox.BeginInvoke(append);
else
append();
}

Related

Wpf async await ui is frozen

I writing a WPF desktop application and I used async await to keep my UI update.
its works OK for 5 or 6 sec but after that UI freezing but background code is running normally.
await Task.Run(() =>
{
result = index.lucene_index(filepath, filename, fileContent);
if (result) {
updateResultTextBox(filename);
Task.Delay(1000);
}
});
and updateResultTextBox is
private void updateResultTextBox(string _filename)
{
sync.Post(new SendOrPostCallback(o =>
{
result_tbx.Text += "Indexed \t" + (string)o + "\n";
result_tbx.ScrollToEnd();
}), _filename);
}
Your question is less then clear. So I have to guess. My only guess at this time: GUI write overhead.
Writing the GUI is not cheap. If you only do it once per user triggered event, you do not notice it. But once you do it in a loop - even one that runs in a seperate task or thread - you will notice it. I wrote this simple Windows Forms example to showcase the difference:
using System;
using System.Windows.Forms;
namespace UIWriteOverhead
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int[] getNumbers(int upperLimit)
{
int[] ReturnValue = new int[upperLimit];
for (int i = 0; i < ReturnValue.Length; i++)
ReturnValue[i] = i;
return ReturnValue;
}
void printWithBuffer(int[] Values)
{
textBox1.Text = "";
string buffer = "";
foreach (int Number in Values)
buffer += Number.ToString() + Environment.NewLine;
textBox1.Text = buffer;
}
void printDirectly(int[] Values){
textBox1.Text = "";
foreach (int Number in Values)
textBox1.Text += Number.ToString() + Environment.NewLine;
}
private void btnPrintBuffer_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(10000);
MessageBox.Show("Printing with buffer");
printWithBuffer(temp);
MessageBox.Show("Printing done");
}
private void btnPrintDirect_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(1000);
MessageBox.Show("Printing directly");
printDirectly(temp);
MessageBox.Show("Printing done");
}
}
}
If you start a lot of those tasks and they suddenly all return 5-6 seconds in the process, you might just plain overload the GUI thread with the sheer amount of write operations.
I actually had that issue with my very first attempt at Multithreading. I did proper Multthreading, but I still overloaded the GUI thread wich made it appear I had failed.
there is something very strange on this code. Anyway, here are my two cents:
var text = await Task.Run(() =>
{
result = index.lucene_index(filepath, filename, fileContent);
if (result) {
return filename;
}
return string.Empty;
});
if (!string.IsNullOrEmpty(text)) {
result_tbx.Text += $"Indexed \t {text} {Environment.NewLine}";
result_tbx.ScrollToEnd();
}
Still a code smell...

C# Decoding X10 Code

I like to decode X10 Code on the Raspberry Pi using C# on Windows 10 IoT but I haven no experience with RF decoding, so this is new territory for me.
I came across this post and I tried to convert this into C# code, but I had no success. Does anyone know how to decode this X10 Code correctly using C#, or can someone point me to the right Protocol specifications.
Here is the code I am currently using, however the ValueChanged Event is not called.
public static void Sniff(uint gpioPinNumb)
{
Task.Run(() => {
using (GpioPin pin = GpioController.GetDefault().OpenPin((int)gpioPinNumb, GpioSharingMode.Exclusive))
{
pin.SetDriveMode(GpioPinDriveMode.Input);
Stopwatch sw = Stopwatch.StartNew();
long elapsedMicrons = 0;
int[] states = new int[67];
int[] durations = new int[67];
uint changeCount = 0;
bool lockPassed = false;
bool isLock = false;
pin.ValueChanged += (GpioPin sender, GpioPinValueChangedEventArgs args) =>
{
elapsedMicrons = sw.ElapsedTicks / 10;
sw.Restart();
//Debug.WriteLine(elapsedMicrons);
if (elapsedMicrons > 25000 && !lockPassed && !isLock)
{
//X10 lock started
changeCount = 0;
durations[changeCount++] = (int)elapsedMicrons;
isLock = true;
Debug.WriteLine("Lock Started");
Debug.WriteLine("");
}
else if (isLock)
{
if (changeCount >= durations.Length)
{
isLock = false;
changeCount = 0;
Debug.WriteLine("===============================");
for (int i = 0; i < durations.Length; i++)
{
Debug.Write(durations[i++]);
Debug.Write(" ");
}
Debug.WriteLine("");
}
else
{
durations[changeCount++] = (int)elapsedMicrons;
}
}
};
}
});
}
Here is the code I am currently using, however the ValueChanged Event
is not called.
This issue caused by using statement that the C# "using" statement results in a call to Dispose(). This is the same as Close(). It also causes the object itself to go out of scope as soon as Dispose is called.
For safety you can move pin out of Sniff method like this:
private static GpioPin pin;
public static void Sniff(uint gpioPinNumb)
{
Task.Run(() => {
pin = GpioController.GetDefault().OpenPin((int)gpioPinNumb, GpioSharingMode.Exclusive);
pin.SetDriveMode(GpioPinDriveMode.Input);
...
...

How to make run real time and faster refresh method with timer

I have script for refresh network with object label and panel but in script using looping mode with 'for'. I want to this real time refresh for 1 sec or 5 sec but because using 'for' make this procces need more time and get stuck screen. how to make the solution more quickly and in real time?
Thanks
public PosPing()
{
InitializeComponent();
RefreshPOS.Tick += new EventHandler(CheckPOSUG);
RefreshPOS.Start();
}
private void CheckPOSUG(object sender, EventArgs e)
{
Panel[] panelUG = new Panel[]{pnlPOSUG1,pnlPOSUG2,pnlPOSUG3,pnlPOSUG4,pnlPOSUG5,pnlPOSUG6,pnlPOSUG7,pnlPOSUG8};
Label[] LabelUG = new Label[]{lblUG1,lblUG2,lblUG3,lblUG4,lblUG5,lblUG6,lblUG7,lblUG8};
Label[] lblSpdUG = new Label[] { lblSpdUG1, lblSpdUG2, lblSpdUG3, lblSpdUG4, lblSpdUG5, lblSpdUG6, lblSpdUG7, lblSpdUG8 };
for (int x = 0; x < 8;x++ )
{
string IP = "192.168.135.1" + (x + 1).ToString();
var ping = new Ping();
var reply = ping.Send(IP, 10 * 1000);
LabelUG[x].Text = "POSBMS10" + x.ToString();
if (reply.Status == IPStatus.Success)
{
lblSpdUG[x].Text = reply.RoundtripTime.ToString() + " " + "ms";
panelUG[x].BackColor = Color.FromName("Lime");
}
else
{
lblSpdUG[x].Text = "Nonaktif";
panelUG[x].BackColor = Color.FromName("ButtonHighlight");
}
}
}
Without a good, minimal, complete code example, it's hard to know for sure how to best answer your question. But it looks like you are trying to ping eight different servers, which are represented by eight set of controls in your form.
If that is correct, then I agree with commenter Hans Passant that you should be using the SendPingAsync() method instead. This will allow you to execute the pings asynchronously, without blocking the UI thread, so that your program can remain responsive.
Because you are dealing with eight different servers, it makes sense to me that you should execute the eight pings asynchronously. To accomplish this, I would refactor the code a bit, putting the server-specific loop body into a separate method, so that each instance can be run concurrently.
Implementing it that way would look something like this:
private async void CheckPOSUG(object sender, EventArgs e)
{
Panel[] panelUG = new Panel[]{pnlPOSUG1,pnlPOSUG2,pnlPOSUG3,pnlPOSUG4,pnlPOSUG5,pnlPOSUG6,pnlPOSUG7,pnlPOSUG8};
Label[] LabelUG = new Label[]{lblUG1,lblUG2,lblUG3,lblUG4,lblUG5,lblUG6,lblUG7,lblUG8};
Label[] lblSpdUG = new Label[] { lblSpdUG1, lblSpdUG2, lblSpdUG3, lblSpdUG4, lblSpdUG5, lblSpdUG6, lblSpdUG7, lblSpdUG8 };
Task[] tasks = new Task[8];
for (int x = 0; x < 8; x++)
{
tasks[x] = PingServer(x, panelUG[x], LabelUG[x], lblSpdUG[x]);
}
try
{
await Task.WhenAll(tasks);
}
catch (Exception e)
{
// handle as appropriate, e.g. log and exit program,
// report expected, non-fatal exceptions, etc.
}
}
async Task PingServer(int index, Panel panel, Label ugLabel, Label spdLabel)
{
// NOTE: String concatenation will automatically convert
// non-string operands by calling calling ToString()
string IP = "192.168.135.1" + (index + 1);
var ping = new Ping();
var reply = await ping.SendPingAsync(IP, 10 * 1000);
ugLabel.Text = "POSBMS10" + x;
if (reply.Status == IPStatus.Success)
{
spdLabel.Text = reply.RoundtripTime + " ms";
// The Color struct already has named properties for known colors,
// so no need to pass a string to look Lime up.
panel.BackColor = Color.Lime;
}
else
{
spdLabel.Text = "Nonaktif";
panel.BackColor = Color.FromName("ButtonHighlight");
}
}

c# 2 events with same nameļ¼Œ got chaos at running time, how should i avoid this?

I have a method "Add2List", who creates a ManualResetEvent and stores it in SortedList of a instance, then waits for signaling, then do some work and dispose the event.
I have another method "DoSomething", who listens to remote server and then signals the stored manual events according to Guid.
in the multithreading context, multi threads calls method "Add2List", so in the sortedlist there may have several manual event with same name at the same moment. But this may cause chaos. How should i avoid this?
To be simpler, i wrote this test code:
Class Program
{
static void Main(string[] args)
{
StringBuilder str = new StringBuilder();//a string to record what happened
//test iteratively
for(int i=0;i<100;i++)
{
EventHolder holder = new EventHolder();
Signaler ob2 = new Signaler();
Thread th1 = new Thread(holder.Add2List);
Thread th2 = new Thread(holder.Add2List);
Thread th3 = new Thread(ob2.DoSomething);
th1.Start(1);
th2.Start(2);
th3.Start();
//Make sure all thread is ended before the next iteration.
while(th1.IsAlive){ Thread.Sleep(200); }
while(th2.IsAlive){ Thread.Sleep(200); }
while(th3.IsAlive){ Thread.Sleep(200); }
}
Console.Read();
}
public class EventHolder
{
static SortedList<int, ManualResetEvent> MyManualEventList = new SortedList<int, ManualResetEvent>();
public EventHolder()
{
MyManualEventList = new SortedList<int, ManualResetEvent>();
Signaler.SignalMyManualEvent += OnSignalMyManualEvent;
}
void OnSignalMyManualEvent(int listindex)
{
try { MyManualEventList[listindex].Set(); }
catch(Exception e)
{
Console.WriteLine("Exception throws at " + System.DateTime.Now.ToString() +" Exception Message:"
Console.WriteLine(e.Message);
int temp = 0; //*Here is a breakpoint! To watch local variables when exception happens.
}
}
public void Add2List(object listindex)
{
ManualResetEvent MyManualEvent = new ManualResetEvent(false);
MyManualEvent.Reset();
MyManualEventList.Add((int)listindex, eve);
//in this test, this countdownevent need to be signaled twice, for it has to wait until all 2 event been added to MyManualEventList
Signaler.StartTrySignal.Signal();
MyManualEvent.WaitOne();
Console.WriteLine("Event" + ((int)listindex).ToString() + " been detected at " + System.DateTime.Now.Tostring());
MyManualEvent.Dispose();
}
}
public class Signaler
{
public delegate void Signalhandler(int listindex);
public static event Signalhandler SignalMyManualEvent;
public static CountDownEvent StartTrySignal = new CountDownEvent(2); // signaled twice so that the 2 manual events were added to sortedlist
void RaiseSignalMyManualEvent(int listindex)
{
var vr = SignalMyManualEvent;
if(vr != null)
vr(listindex);
}
int i = 0, j = 0, k = 0;
// here i use 2 prime numbers to simulate the happening of 2 random events
public Signaler()
{
StartTrySignal.Reset();
}
public void DoSomething()
{
StartTrySignal.Wait(); // wait for the 2 manual events been added to sortedlist
//To signal MyManualEventList[1] or MyManualEventList[2]
while(i + j == 0)
{
Random rnd = new Random();
k = rnd.Next();
if(k % 613 == 0) { i = 1; Console.WriteLine("Event1 Raised!"; RaiseSignalMyManualEvent(1); }
else if(k % 617 == 0) { j = 1; Console.WriteLine("Event1 Raised!"; RaiseSignalMyManualEvent(2); }
}
//if MyManualEventList[1] has not been signaled, wait something to happen, and signal it.
while(i == 0)
{
Random rnd = new Random();
k = rnd.Next();
if(k % 613 == 0)
{
i = 1;
if(j>0)
{
m++;
Console.WriteLine("All 2 Events Raised! - iteration " + m.ToString());
}
RaiseSignalMyManualEvent(1);
}
}
//if MyManualEventList[2] has not been signaled, wait something to happen, and signal it.
while(j == 0)
{
Random rnd = new Random();
k = rnd.Next();
if(k % 617 == 0)
{
j = 1;
m++;
Console.WriteLine("All 2 Events Raised! - iteration " + m.ToString());
RaiseSignalMyManualEvent(2);
}
}
}
}
public class Counter //Provide a number to record iteration
{
public static int m = 0;
}
}
Result:
Sorry for do not have enough reputation to post images.
At the line where there's a breakpoint, system throws exception " the given key is not in dictionary". this exception happens randomly, sometimes because th1 disposed <2, MyManualEvent> or th2 disposed <1, MyManualEvent> , sometimes none has been disposed but it just cannot find anyone.
I run this program 3 times, exception happens at iteration12, iteration45, and iteration0 (at the beginning).
OK 2 answers
1: Your code returns "Event 1" after "All events", because the two console.writelines are in a race condition (the last while loop is never iterated)
2: the 'System' distingushes between the two ManualResetEvent objects becuase it references the SortedList you put them in. ie.
static SortedList<int, ManualResetEvent> MyManualEventList
= new SortedList<int, ManualResetEvent>();
public EventHolder() { Signaler.SignalMyManualEvent
+= OnSignalMyManualEvent; }
void OnSignalMyManualEvent(int listindex)
{
MyManualEventList[listindex].Set();
}
when you raise event 1 you call set on Item 1 in the SortedList and when you raise Event 2 you call set on Item 2 in the list.
this is bad because the calling code has no idea which thread it is allowing to continue and you could well get a null exception

C# application slows Down after 20-30 mins?

I have c# application which reads data from serial port. I have put serial read handler in timer with interval 1 second , because data coming every 1 second
on timer I calling
delegate void SetTextCallback(string text);
ReceivedText(serialPort1.ReadExisting());
I also showing received data in richtextbox just to check it getting proper data or not.
But after 15-20 mins application slows down wont even respond.
private void ReceivedText(string text)
{
if (this.rtbReceived.InvokeRequired)
{
SetTextCallback x = new SetTextCallback(ReceivedText);
this.Invoke(x, new object[] { (text) });
}
else
{
this.rtbReceived.Text += text;
serialdata = text;
if (serialdata.Length > 0 &&
serialdata.Length < 42 &&
serialdata.Contains("#") ||
serialdata.StartsWith(" #"))
{
serialdata.Trim();
splitdata = serialdata.Split(' ');
try
{
txtBathTemp.Text = splitdata[3];
txtBaroPressure.Text = splitdata[4];
double stemp = double.Parse(splitdata[5]);
txtSampleTemp.Text = (Math.Round(stemp, 2)).ToString();
}
catch (Exception EX)
{
MessageBox.Show(ex.Message);
}
}
}
}
There is a chance that this.rtbReceived.Text grows up after some time. Even if it doesn't use huge amount of memory, constantly manipulating String is not efficent. Have you considered using StringBuilder instead?

Categories