Threading in wpf GUI thread is too slow - c#

My application has work to do in background in another thread and the Gui drawing result from list the background thread fill this list
In initialization I made the background thread and when I press button in Gui this thread begin working ; and I click on another buttom to read result while the background thread working but The GUI is very very slow to response to result.
is there any solution I want my results display on GUI faster ?
my code:
Thread startdrawingthread = new Thread(StartDrawing);
public MainWindow()
{
InitializeComponent();
}
private void bt_draw_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (ch_single.IsChecked == true || ch_entire.IsChecked == true)
{
currentMode = "";
startdrawingthread.Start();
//StartDrawing();
real_area.DrawingArea.Children.Clear();
real_area.DrawGrid(20);
}
}
private void bt_single_next_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (GlobalV.isfinished == false)
{
while (true)
{
if (GlobalV.Attatched_Elements.Count > 0)
{
try
{
real_area.DrawingArea.Children.Clear();
real_area.DrawGrid(20);
real_area.DrawElement(GlobalV.Attatched_Elements[i]);
i++;
}
catch
{
}
break;
}
}
}
}

You've committed sin #1 in asynchronous programming.
You have a busy loop. Instead of waiting for GlobalV.Attatched_Elements.Count to change, you constantly, non-stop ask "is it nonzero now? is it nonzero now? is it nonzero now? is it nonzero now? is it nonzero now? is it nonzero now? is it nonzero now? is it nonzero now?", as fast as the CPU can do it.
In other words, you're wasting a lot of execution time.
What you want to do is simply subscribe to an event telling you when Count changes. Then, when it changes, you check if it is nonzero, and perform the necessary processing.

The problem is, as long as GlobalV.Attatched_Elements.Count is zero, your event handler goes through an endless loop of while (true).
I guess that GlobalV.Attatched_Elements.Count is set somewhere in StartDrawing, but you can not busy-wait like this until it gets greater than zero. You should perhaps remove the whole if (GlobalV.isfinished == false) and while (true) blocks and simply do the following, which especially does nothing if there is nothing to do:
private void bt_single_next_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (GlobalV.Attached_Elements.Count > 0)
{
...
}
}
maybe with also locking the collection for thread-safe access:
private void bt_single_next_Click(object sender, System.Windows.RoutedEventArgs e)
{
lock (GlobalV.Attached_Elements)
{
if (GlobalV.Attached_Elements.Count > 0)
{
...
}
}
}

Related

How to start a process only after one process has completed?

I have 2 functions I created which does specific works.
I call these functions on timers. But before function 1 completes, function 2 starts processing. How can I wait till 1 completes before starting 2.
Here is my code:
private void btnrun_Click(object sender, EventArgs e)
{
try
{
_bat.ShowDialog();
StrBatchNumber = _bat.GlobalBatchNumber;
DialogResult _diaresult = _bat.DialogResult;
if (_diaresult == DialogResult.OK)
{
if (StrBatchNumber == "")
{
MessageBox.Show("Please enter a batch number", "Batch Number Missing", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
btnstartrobo.PerformClick();
btnautostart.PerformClick();
}
}
}
catch(Exception)
{
}
}
System.Windows.Forms.Timer tmrfirst = new System.Windows.Forms.Timer();
private void btnautostart_Click(object sender, EventArgs e)
{
tmrfirst.Interval = 1000;
tmrfirst.Tick += new EventHandler(tmrfirst_Tick);
tmrfirst.Start();
}
private void tmrfirst_Tick(object sender, EventArgs e)
{
btnchecksignal.PerformClick();
Thread.Sleep(100);
if (textBox8.Text.Contains("+1"))
{
button14.PerformClick();
Thread.Sleep(20);
button42.PerformClick();
Thread.Sleep(300);
btnautostart.PerformClick();
}
}
I tried giving thread.sleep in between, but it doesn't work. How can I fix this? Please help.
The reason why your solution is not working correctly, is because both operations run in the same thread. Therefore your Thread.Sleep(100) is making both functions wait, not making the order change but delaying the complete program execution.
The easiest solution to solve this would be Multithreading (see the documentation on how to implement another thread here and how to start it running a function here)
Like this you can add the new Thread to the end of your first method or insert it into a helper method to run it only after method 1 has completed. If you call the same function several times, maybe check if the thread already exists before creating a new one or simply close it every time your second function is finished.

C# windows formmain thread can't run 2 processes at once/ can't find how to make the work done

I have trouble making the main thread of my program in my windows form work properly, as it freezes and does not paint my objects for a while. I will explain it with a dummy example.
Let's say we have :
a train thread running around a track,
a wagon thread waiting in a place on the same track,
and a main thread painting the objects in the windows form.
the train and wagon threads start as follow :
public PanelThread train, wagon;
private Thread thread1, thread2;
train = new PanelThread(new Point(10, 10),
150, Direction.West, Track.track1, pnl1, typetrain.loco,
Color.Blue,
semaphore
);
wagon = new PanelThread(new Point(390, 390),
150, Direction.West, Track.track1, pnl1, typetrain.loco,
Color.Blue,
semaphore
);
thread1 = new Thread(new ThreadStart(train.Start));
thread2 = new Thread(new ThreadStart(wagon.Start));
thread1.Start();
thread2.Start();
And in the PanelThread class : (the code is specific and only added as asked in comments)
public void Start()
{
Color signal = Color.Red;
Thread.Sleep(delay);
if (this.locwag == typetrain.loco)
{
work();
}
else
{
for (;;)
{
if (greenclicked == true)
{
workwagon();
break;
}
}
}
}
Now, when we click on a button, we launch a function like as follow :
private void button7_Click(object sender, EventArgs e)
{
for(;;)
{
if(train.variable1 == true)
{
break;
}
}
wagon.variable2 = true;
}
the variable1 is always false except when the train is on the same place as the wagon (done by checking if the train is at a certain point in a for loop, like at the end of the second passage i.e counter_variable = 2).
Now, the thing is that the for loop is taking all the place in the ain thread and not letting it paint the objects, even though the other thread still work, and the painting resumes after the function is finished.
I tried putting this loop in a function in the train thread launched by the button7_clicked function like this :
private void button7_Click(object sender, EventArgs e)
{
train.waitingfunction();
wagon.variable2 = true;
}
But the result is the same as the function waits for the waitingfunction() to be done.
I then thought I would need to completely delegate the work on another thread, using invoke, but I admit I do not understand yet how it exactly works. so I wrote it like this, using invoke on the panel.
private void button7_Click(object sender, EventArgs e)
{
if (panel.InvokeRequired)
{
panel.Invoke(new MethodInvoker(delegate{train.waitingfunction();}));
}
wagon.variable2 = true;
}
As of now there is no freeze anymore but the wagon automatically starts, I am guessing the function never goes in the if statement and I am now completely lost. Any idea on how to work around the problem ?
UPDATE : here is the answer, in the Waitingfunction called waitingwagon in my program, I used AutoResetEvent like this :
public void waitingwagon()
{
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
while (!autoResetEvent.WaitOne(TimeSpan.FromSeconds(0.1)))
{
if (waitinggreen == true)
{
break;
}
}
}
what you want to avoid is for(;;) in your main thread, because that blocks your thread ...
your 2nd thread (wagon) basically has to do nothing, until that status changes, so you could use a event wait handle (e.g. manual/auto reset event) and block your wagon thread with that until that event fires ...
but of course if you have side constraints like "a button has to be clicked" etc you will have to add additional logic to handle that... it's not really possible to provide a working example for your specific problem, since you did not provide a compilable sample, but if you google event wait handles and look for examples on manualresetevent or autoresetevent, you should find something you can adapt

While sequence inside a timer tick in C#

I have a timer of 1 second in C#, with a while sequence in it. My question is if the while sequence is not finished before 1 second, will the timer tick, and restart the while from the beginning?
The part of the code is below, and what it does is that it cycles through the selected objects and changes something. So, if there are a lot of objects selected and I need more than 1 second to change them, will they all be changed?
P.S. I actually want the loop to be broken; a large number of objects will be selected only by mistake, but I just want to be sure that I avoid this possibility. :)
private void timer1_Tick(object sender, EventArgs e)
{
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext())
{
if (myEnum.Current != null)
{....}
}
}
Yes, timer ticks can happen concurrently. This means that your timer must be thread-safe.
Except for the UI timer classes (WinForms/WPF). Their tick functions run on the UI thread. With DoEvents you can cause reentrancy even there which is another reason to avoid DoEvents.
From the name of the handler I assume you are using System.Windows.Forms.Timer which is single-threaded. That means the Tick event will fire after the previous one has ended. To break the loop, you will have to execute the code in another thread an use an exit condition.
This is how I usually do it:
private bool running;
private bool restart;
private void DoWork(object item)
{
running = true;
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext() && !restart)
{
//do your stuff
if (myEnum.Current != null) {....}
}
if(restart)
{
restart = false;
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if (running)
restart = true;
else
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
A workaround would be to disable the timer at the top of the while event, and re-enable it as you exit the while event.
The while loop will not be broken because the timer has ticked again. But in any case, your best bet would be to disable the timer at the beginning of the event handler, and re-enable it again at the end.
You could always try something similar to this instead, that way you void having multiple timers tick over and kick off processes. Written in Notepad so please excuse any massive spelling mistakes
private Timer _systemTimer = null;
public MyApp()
{
_systemTimer = new Timer("how ever you set your 1 second);
// Create your event handler for when it ticks over
_systemTimer.Elapsed += new ElapsedEventHandler(systemTimerElapsed);
}
protected void systemTimerElapsed(object sender, ElapsedEventArgs e)
{
_systemTimer.Stop();
//Do what you need to do
_systemTimer.Start();
//This way if it takes longer than a second it won't matter, another time won't kick off until the previous job is done
}
I will make it very easy for you;use Thread.Sleep() in another background thread and it is done!
If you know when are you finish than just use AutoResetEvent to keep threads in sync.
If you do not have any control on the update no callback , time is unknown I suggest to increase your timer interval!
var thread = new Thread((ThreadStart)delegate
{
While(true)
{
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext())
{
if (myEnum.Current != null)
{....}
}
Thread.Sleep(1000);
}
}
thread.Start();
Get each char from string from txtString and write on label one by one char with timerControl
int g = 0;
private void timerString_Tick(object sender, EventArgs e)
{
string a = txtString.Text;
int em = txtString.TextLength;
if (g < em)
{
lblString.Text = lblString.Text + a[g];
g++;
}
else timerString.Stop();
}
Call from
private void btnStringStart_Click(object sender, EventArgs e)
{
timerString.Start();
lblString.Text = "";
}

C# BackgroundWorker

I have a button that on click event I get some information from the network.
When I get information I parse it and add items to ListBox. All is fine, but when I do a fast double-click on button, it seems that two background workers are running and after finishing all work, items in the list are dublicated.
I want to do so that if you click button and the proccess of getting information is in work, this thread is stopping and only after first work is completed the second one is beginning.
Yes, I know about AutoResetEvent, but when I used it it helped me only one time and never more. I can't implement this situation and hope that you will help me!
Now I even try to make easier but no success :( : I added a flag field(RefreshDialogs)(default false), when the user clicks on button, if flag is true(it means that work is doing), nothing is doing, but when flag field is set to false, all is fine and we start a new proccess.
When Backgroundwork completes, I change field flag to false(it means that user can run a new proccess).
private void Message_Refresh_Click(object sender, EventArgs e)
{
if (!RefreshDialogs)
{
RefreshDialogs = true;
if (threadBackgroundDialogs.WorkerSupportsCancellation)
{
threadBackgroundDialogs.CancelAsync();
}
if (!threadBackgroundDialogs.IsBusy)
{
downloadedDialogs = 0;
threadBackgroundDialogs = new BackgroundWorker();
threadBackgroundDialogs.WorkerSupportsCancellation = true;
threadBackgroundDialogs.DoWork += LoadDialogs;
threadBackgroundDialogs.RunWorkerCompleted += ProcessCompleted;
threadBackgroundDialogs.RunWorkerAsync();
}
}
}
void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
{
RefreshDialogs = false;
}
So you want to keep the second process running while the first works, but they shouldn't disturb each other? And after the first one finishes the second one continues?
Crude way: While loop:
if (!RefreshDialogs)
{
RefreshDialogs = true;
this becomes:
while(RefreshDialogs)
{
}
RefreshDialogs = true;
After you set it false the second process wwill jump out of the while. (Note this is extremly inefficent since both processes will be running all the time, i'm pretty sure the second one will block the first one, but with multitasking now it shouldn't, if it block use a Dispatcher.Thread)
Elegant way: Use A Semaphore
http://msdn.microsoft.com/de-de/library/system.threading.semaphore%28v=vs.80%29.aspx
If you find it impossible to have both processes running at the same time, or want another way:
Add an Array/List/int and when the second process notices there is the first process running, like with your bool, increase your Added variable, and at the end of the process, restart the new process and decrese the variable:
int number;
if (!RefreshDialogs)
{
RefreshDialogs = true;
your code;
if(number > 0)
{
number--;
restart process
}
}
else
{
number++;
}
I have to admit, i like my last proposal the most, since its highly efficent.
Make your thread blocking. That is easy;
lock(someSharedGlobalObject)
{
Do Work, Exit early if cancelled
}
This way other threads will wait until the first thread releases the lock. They will never execute simultaneously and silently wait until they can continue.
As for other options; why not disable the button when clicked and re-enable it when the backgroundworker completes. Only problem is this does not allow for cancelling the current thread. The user has to wait for it to finish. It does make any concurrency go away very easily.
How about this approach?
Create a request queue or counter which will be incremented on every button click. Every time that count is > 0. Start the background worker. When the information comes, decrement the count and check for 0. If its still > 0 restart the worker. In that your request handler becomes sequential.
In this approach you may face the problem of continuous reference of the count by two threads, for that you may use a lock unlock condition.
I hav followed this approach for my app and it works well, hope it does the same for you.
I'm not an Windows Phone expert, but as I see it has support for TPL, so following code would read nicely:
private object syncRoot =new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
latestTask = Task.Factory.StartNew(action);
else
latestTask = latestTask.ContinueWith(tsk => action());
}
}
Use can use semaphores
class TheClass
{
static SemaphoreSlim _sem = new SemaphoreSlim (3);
static void Main()
{
for (int i = 1; i <= 5; i++)
new Thread (Enter).Start (i);
}
static void Enter (object name)
{
Console.WriteLine (name + " wants to enter");
_sem.Wait();
Console.WriteLine (name + " has entered!");
Thread.Sleep (1000 * (int) name );
Console.WriteLine (name + " is leaving");
_sem.Release(); }
}
}
I found the solution and thanks to #Giedrius. Flag RefreshingDialogs is set to true only when proccess is at the end, when I added items to Listbox. The reason why I'am using this flag is that state of process changes to complete when the asynchronous operation of getting content from network(HttpWebRequest, method BeginGetRequestStream) begins, but after network operaion is complete I need to make UI operations and not only them(parse content and add it to Listbox)My solution is:
private object syncRoot = new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
{
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
else if(latestTask.IsCompleted && !RefreshingDialogs)
{
RefreshingDialogs = true;
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
}
}
private void Message_Refresh_Click(object sender, EventArgs e)
{
Action ac = new Action(LoadDialogs2);
EnqueueAction(ac);
}

C# wait 1 second

Is there such a function like sleep(seconds) but it wouldn't block UI updates?
I have a code like this and if I put threading sleep after (letters.Children[Words[index].index] as TextBlock).Text = Words[index].LetterCorrect; (I want to sleep after that) it just waits 1 sec and then UI gets updates, but I dont want that.
private void Grid_Click(object sender, RoutedEventArgs e)
{
if (index == Words.Count() - 1) return;
if ((((e.Source as Button).Content as Viewbox).Child as Label).Content.ToString() == Words[index].LetterCorrect)
{
(letters.Children[Words[index].index] as TextBlock).Text = Words[index].LetterCorrect;
letters.Children.Clear();
LoadWord(++index);
this.DataContext = Words[index];
}
}
Try a Timer and have the Elapsed callback execute the code you want to happen after the one second.
Create a working thread that does the work for you and let that thread sleep for the desired time before going to work
e.g.
ThreadPool.QueueUserWorkItem((state) =>
{
Thread.Sleep(1000);
// do your work here
// CAUTION: use Invoke where necessary
});
Put the logic itself in a background thread separate from the UI thread and have that thread wait.
Anything in the UI thread that waits 1 second will lock up the entire UI thread for that second.
Use an async scheduled callback:
private void Grid_Click(object sender, RoutedEventArgs e)
{
if (index == Words.Count() - 1) return;
if ((((e.Source as Button).Content as Viewbox).Child as Label).Content.ToString() == Words[index].LetterCorrect)
{
(letters.Children[Words[index].index] as TextBlock).Text = Words[index].LetterCorrect;
Scheduler.ThreadPool.Schedule(schedule =>
{
letters.Children.Clear();
LoadWord(++index);
this.DataContext = Words[index];
}, TimeSpan.FromSeconds(1));
}
}
Not sure what framework you are using, but if you are using Silverlight or WPF, have you considered playing an animation that reveals the correct letter or does a fade sequence that takes 1000ms?

Categories