Freezing UI and odd thread behavior (WPF) - c#

I am building an application with WPF and C# and I have run into an odd problem. There are multiple threads in my application, many of which are created through System.Timer timers. There is a particular action I can take that will cause the UI of my application to freeze; my UI will freeze permanently when this happens. The oddest thing about this though is that if I check the number of available threads with Threadpool.GetAvialbaleThreads, the number of available threads will continuously diminish if I don't stop the application. All of the threads in my application are created either via timer or the Task.StartNew method.
There are several parts of my code that spin up new threads, I will try to show all of them here in an abbreviated way.
DataManager.cs
// Two System.Timers.Timer(s) handle generating data values on 3 second and 1.5 second intervals.
_averageTimer = new System.Timers.Timer(1000 * 3);
_averageTimer.Elapsed += GenerateNewAveragePoint;
_averageTimer.Enabled = false;
_flowGenTimer = new System.Timers.Timer(1000 * 1.5);
_flowGenTimer.Elapsed += GenerateNewFlowSet;
_flowGenTimer.Enabled = false;
// I also have a primary work loop in this class which is created via Task
// This function runs continuously
Task.Run(() => ProcessData());
// I also send off a Task to do file I/O about every 3 seconds
Task.Run(() =>
{
lock (_sharedData.FileLock)
{
_continuousFileManager.WriteDataSubset(tmpData);
}
});
// Finally, I have a similar file I/O function to the one above, but it is
// called in the timer which fires every 3 seconds
Task.Run(() =>
{
lock (_sharedData.FileLock)
{
_averageFileManager.WriteDataSubset(tmpData);
}
});
So from this class it appears that I probably utilize a max of 6 threads.
In another class I have 3 calls to Dispatcher.Invoke
AdvancedPanel.cs
// RealtimeDataFlowItems is an ObservableCollection
Application.Current.Dispatcher.Invoke(delegate
{
RealtimeDataFlowItems.Insert(0, avgFlow);
});
// RealtimeDataHRItems is an ObservableCollection
Application.Current.Dispatcher.Invoke(delegate
{
RealtimeDataHRItems.Insert(0, avgFlow);
});
// RealtimeDataTimeItems is an ObservableCollection
Application.Current.Dispatcher.Invoke(delegate
{
RealtimeDataTimeItems.Insert(0, avgFlow);
});
In another class I have one call to Dispatcher.Invoke
DataInfo.cs
Application.Current.Dispatcher.Invoke(delegate
{
IndicatorPoints = new PointCollection(new[] { /* Removed for brevity */});
}
In another class there are two System.Timers.Timer(s) which execute at intervals of 15 ms and 2 seconds.
PlotData.cs
_plotTimer = new System.Timers.Timer(15);
_plotTimer.Elapsed += ProcessLoop;
_plotTimer.Enabled = false;
_boundsTimer = new System.Timers.Timer(1000 * 2);
_boundsTimer.Enabled = false;
_boundsTimer.Elapsed += CheckYAxisBounds;
Also, this class utilizes the OxyPlot plotting library in order to present realtime data in the UI. OxyPlot obviously has to modify the UI, so will be performing actions on the UI thread.
As a final note, I use Caliburn.Micro in my application and make use of its EventAggregator heavily. Each time I wish to publish a message a new Task is started with the StartNew method. Nearly all of the classes in my application make use of the EventAggregator in some capacity, so there are several threads that become utilized from these actions.
I hope this information is helpful, please let me know if there is more that I should provide. I am hoping that one of you could provide me any insight on what might be happening, and how I might be able to go about debugging and solving my UI freezing issue. Thank you so much for your help!

Related

Trying to solve a core affinity problem results in UI stalling under heavy CPU load

I have literally no experience in threading, so bear with me, please.
I'm making a monitoring/testing tool, that monitors hardware sensors and uses affinity masks and for loop to cycle through the cores one by one running a full-load single-core stress test.
The problem is, that when the user starts the test, and affinity is set, instead of assigning just the test method to that core, it assigns the entire program, which means UI can run only on the core that is currently tested and is under full load.
I guess it's clear that UI is just stalling during the test, and labels that output monitoring data are frozen, while it's crucial to have relevant readings during the test because this is the main purpose of this program.
After some research, I figured that I need to use threading but I never worked with it before.
Here is my shortened code. The problem is, that when I use threading on any method that contains labels, it throws the error "Cross-thread operation not valid: Control 'CPUTempTDie' accessed from a thread other than the thread it was created on". I tried to start Report sensors in a new thread, but it doesn't help. I literally tried to start in a new thread every method and label that is involved, but it's either doesn't help or control score (score - is a result returned by TestMethod to compare it with the correct number to confirm stability) or the program just skips some part of the code and just says "Done".
The question is: Is it possible to set just a TestingMethod to a particular core, allowing the rest of the program (including UI) to use any other free core, and if not, what exactly should I start in a new thread to let UI update under the load?
//the method below updates labels and calls ReportSensors method that reads
//sensors on a timer tick
private void Monitoring()
{
sensor.ReportSensors(); //calls Method that reads sensors
//Two labels below are stalling when TestingMethod runs
CPUTempTDie.Value = (int)sensor.CpuTemp;
FrequencyLabel.Text = sensor.CoreFrequency.ToString("0") + "MHz";
}
private int TestingMethod()
{
while (true)
{
//Performs calculations to generate load, returns the "score"
}
if (timer.Elapsed.TotalSeconds > 60)
{
break;
}
return score;
}
private async void PerCoreTest()
{
try
{
await Task.Delay(3000);
for (int i = 0; i < (numberOfCores); i++)
{
coreCounter++;
Thread.BeginThreadAffinity();
SetThreadAffinityMask(GetCurrentThread(), new IntPtr(intptrVal));
//TestingMethod below being called twice, and results from both runs
//are later compared for consistency.
TestingMethod();
iter1 = score / 10000;
TestingMethod();
iter2 = score / 10000;
maxScore = Math.Max(iter1, iter2);
await Task.Delay(1000);
TestLabel.Text = score.ToString();
//Switches to the next thread mask
}
}
finally
{
Thread.EndThreadAffinity();
}
}
private void TestButton_Click(object sender, EventArgs e)
{
using (Process p = Process.GetCurrentProcess())
p.PriorityClass = ProcessPriorityClass.High;
PerCoreTest();
using (Process p = Process.GetCurrentProcess())
p.PriorityClass = ProcessPriorityClass.Normal;
}
Clarification: My question was closed as a duplicate despite the linked thread doesn't answer my question. I ask to reopen it because:
While "a large number of Remote Calls around 2000 - 3000 calls" mentioned in a linked thread might be heavy on some hardware, it's not the same as hammering the CPU with calculations in the while(true) loop, which squeeze all performance from any kind of hardware living nothing for UI if UI sits on the same core.
Suggested solution in the thread that I allegedly duplicated doesn't resolve the issue, and my original question is completely different: I can not figure out what exactly must be put in a task to make UI run smoothly under the load.
Suggestions from the comments under my thread don't answer the question too. I tried the solution from
Panagiotis Kanavos (see below) but the problem persists:
while (true)
{
await Task.Delay(500);
await Task.Run(() => sesnor.ReportSensors());
}
After researching similar topics it seems like none of them address my particular issue.
You're setting the CPU affinity for the UI thread, then running the test routine on the same thread so it makes sense your UI is hanging during the test. Simplify things and ensure your UI/threading is working properly before you jump into actually performing your test routine.
private int TestingMethod()
{
// set affinity for current thread here when ready
// mock a busy thread by sleeping
System.Threading.Thread.Sleep( 15 * 1000 );
return 42;
}
// don't use `async void`
private async Task PerCoreTest()
{
TestLabel.Text = "Running...";
// we're in the UI thread, so we want to run
// the test in another thread. run a new
// task to do so, await result so the continuation
// will execute back in the UI thread
var score = await Task.Run(() => TestingMethod());
TestLabel.Text = score.ToString();
}
private async Task TestButton_Click(object sender, EventArgs e)
{
await PerCoreTest();
}
Nice and simple. Add something else to the form that updates every second or so or a button you can click to verify the UI is updating properly as the test routine is running.
Once you've verified that the UI isn't locking up, then you may begin adding substance to your test routine. I suggest just getting a working test routine without processor affinity first.
private int TestingMethod()
{
var score = 0;
// set affinity for current thread here when ready
do
{
// your cpu-frying logic
}
while( /* sentinel condition */ )
return score;
}
Again, verify the UI is responsive during the test and you can also verify one of your cores is getting abused. Once all that is verified, you may then set the thread affinity INSIDE the TestingMethod() method's implementation (abstracting it to another method call is fine as well as long as it's called from within the TestingMethod's body and isn't run in a Task or another thread. You can pass the mask into TestingMethod as a parameter from the PerCoreTest method.
This should get you on the right track to doing what you want to do. I suggest you spend some quality time reading about multithreading in general and .NET's threading/asynchronous programming model if you plan on continuing with it in the future.

Multiple Background workers in web forms application

I have a requirement where a client makes a request to a single web page, this web page needs to retrieve the results from two other web pages.
The two web pages that we are requesting info from carry out a process before returning the result, this process can take a few minutes so rather than starting a web request and waiting for it to return and then starting another I want to fire off both requests in background workers and have the results being generated in parallel.
So my code looks something like this (Pseudo code):
var worker1 = new BackgroundWorker();
var worker2 = new BackgroundWorker();
worker1.DoWork += (s, e) => {
//Web Request done here
};
worker2.DoWork += (s, e) => {
//Web Request done here
};
worker1.RunWorkerAsync();
worker2.RunWorkerAsync();
//Some logic here that basically waits for both to return.
Now I noticed that the results were still taking longer to return than I expected so I did a bit of a test and changed the contents of the Dowork to
using (var sw = new StreamWriter(#"c:\temp\TEST\Worker1.txt"))
{
for (int i = 0; i < 1000000; i++)
{
sw.WriteLine($"{i} - {DateTime.Now.ToLongTimeString()}");
}
}
For brevity I wont copy this back out but assume that the file name is changed to worker2.txt in the second workers DoWork()
Its crude I know, but it works, its takes about 3 seconds to write out the time 1 million times so in the first file I see times ranging from Execution Time to Execution Time + 3 seconds
In the second file I can see times ranging from Execution time + 3 Seconds to Execution Time + 6 seconds.
So it’s clear at this point that one worker is being executed first and then the other, but I cannot see why.
More info about the project - Web forms (This is a requirement I have been given and have to stick to) .net 4.5
**Edited to add : **
After coming back to this problem I have had a look at the pages that I am calling and notice that they have aspcompat=true in the page declaration, which I assume is what is causing the issue (They require this, I cant remove it).
What are my options now? Ideally I want to be able to call these pages to run in parallel, is there any way to still achieve this with the aspcompat set to true?
Editing for future readers
Note that the problem that I described above and the code that was provided were correct, the issue that I had was that the pages that I was calling were set to use ASPCOMPAT which forces webforms to work in STA mode which is what was throwing me off.
In the end the code above did work unchanged, the solution was to put the page with the background workers in a separate web application with its own app pool, that page the n used the background workers to call off to the pages running in aspcompat mode in their application pool - its not ideal, but its what we wanted for the live deployment anyway.
You could skip the BackgroundWorker and use Task.WaitAll() instead.
void Main()
{
Task.WaitAll(FirstRequest(), SecondRequest());
}
// Define other methods and classes here
private async static Task FirstRequest()
{
// Do your work for one of the WebRequests here
await Task.Delay(3000);
Console.WriteLine("Done with 1");
}
private async static Task SecondRequest()
{
// Do your work for the second WebRequest here
await Task.Delay(3000);
Console.WriteLine("Done with 2");
}

Threading and collections modification in WPF / C#

I'm currently developing a system in C# / WPF which accesses an SQL database, retrieves some data (around 10000 items) and then should update a collection of data points that is used as data for a WPF chart I'm using in my application (Visifire charting solution, in case anyone was wondering).
When I wrote the straight-forward, single-threaded solution, the system would, as you might expect, hang for the period of time it took the application to query the database, retrieve the data and render the charts. However, I wanted to make this task quicker by adding a wait animation to the user while the data was being fetched and processed using multithreading. However, two problems arise:
I'm having trouble updating my collections and keeping them synchronized when using multithreading. I'm not very familiar with the Dispatcher class, so I'm not very sure what to do.
Since I'm obviously not handling the multi-threading very well, the wait animation won't show up (since the UI is frozen).
I'm trying to figure out if there's a good way to use multi-threading effectively for collections. I found that Microsoft had Thread-Safe collections but none seems to fit my needs.
Also, if anyone have a good reference to learn and understand the Dispatcher I would highly appreciate it.
EDIT:
Here's a code snippet of what I'm trying to do, maybe it can shed some more light on my question:
private List<DataPoint> InitializeDataSeries(RecentlyPrintedItemViewModel item)
{
var localDataPoints = new List<DataPoint>();
// Stopping condition for recursion - if we've hit a childless (roll) item
if (item.Children.Count == 0)
{
// Populate DataPoints and return it as one DataSeries
_dataPoints.AddRange(InitializeDataPoints(item));
}
else
{
// Iterate through all children and activate this function on them (recursion)
var datapointsCollection = new List<DataPoint>();
Parallel.ForEach(item.Children, child => datapointsCollection = (InitializeDataSeries((RecentlyPrintedItemViewModel)child)));
foreach (var child in item.Children)
{
localDataPoints.AddRange(InitializeDataSeries((RecentlyPrintedItemViewModel)child));
}
}
RaisePropertyChanged("DataPoints");
AreDataPointsInitialized = true;
return localDataPoints;
}
Thanks
The Dispatcher is an object used to manage multiple queues of work items on a single thread, and each queues has a different priority for when it should execute it's work items.
The Dispatcher usually references WPF's main application thread, and is used to schedule code at different DispatcherPriorities so they run in a specific order.
For example, suppose you want to show a loading graphic, load some data, then hide the graphic.
IsLoading = true;
LoadData();
IsLoading = false;
If you do this all at once, it will lock up your application and you won't ever see the loading graphic. This is because all the code runs by default in the DispatcherPriority.Normal queue, so by the time it's finished running the loading graphic will be hidden again.
Instead, you could use the Dispatcher to load the data and hide the graphic at a lower dispatcher priority than DispatcherPriority.Render, such as DispatcherPriority.Background, so all tasks in the other queues get completed before the loading occurs, including rendering the loading graphic.
IsLoading = true;
Dispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(delegate() {
LoadData();
IsLoading = false;
}));
But this still isn't ideal because the Dispatcher references the single UI thread of the application, so you will still be locking up the thread while your long running process occurs.
A better solution is to use a separate thread for your long running process. My personal preference is to use the Task Parallel Library because it's simple and easy to use.
IsLoading = true;
Task.Factory.StartNew(() =>
{
LoadData();
IsLoading = false;
});
But this can still give you problems because WPF objects can only be modified from the thread that created them.
So if you create an ObservableCollection<DataItem> on a background thread, you cannot modify that collection from anywhere in your code other than that background thread.
The typical solution is to obtain your data on a background thread and return it to the main thread in a temp variable, and have the main UI thread create the object and fill it with data obtained from the background thread.
So often your code ends up looking something like this :
IsLoading = true;
Task.Factory.StartNew(() =>
{
// run long process and return results in temp variable
return LoadData();
})
.ContinueWith((t) =>
{
// this block runs once the background code finishes
// update with results from temp variable
UpdateData(t.Result)
// reset loading flag
IsLoading = false;
});

Running parallel in background

Main question is: How to run the code within TestingButton_Click on several threads in background (similar to BackgroundWorker) so I will be able to:
1. Get all the raw data to the methods
2. Cancel test for all threads simultaneously
3. Report progress
4. Retrieve all the result tables to main thread.
The following code is within TestingButton_Click
List<Thread> threads = new List<Thread>();
//Testing for each pair
foreach (InterfaceWithClassName aCompound in Group1)
{
foreach (InterfaceWithClassName bCompound in Group2)
{
InstancePair pair = new InstancePair();
//some code
if (testModeParallel)
{
Thread thr = new Thread(TestPairParallel);
thr.Start(pair);
threads.Add(thr);
}
else
{
Thread thr = new Thread(TestPairSerial);
thr.Start(pair);
threads.Add(thr);
}
}
}
while (true)
{
int i = 0;
foreach (Thread thread in threads)
{
if (thread.IsAlive)
break;
i++;
}
if (i == threads.Count)
break;
Thread.Sleep(1000);
}
pairsResultsDataGrid.ItemsSource = tab.DefaultView
User is able to choose what compounds to test so every time I have different number of pairs to test.
I made to different methods TestPairSerial() and TestPairParallel() just in case.
TestPairSerial() structure is
do
{
do
{
} while (isSetbCompaundParams);
} while (isSetaCompaundParams);
//filling up results into tables (main window variables) later to be connected to DataGrids
TestPairParallel() is implemented with InfinitePartitioner and using similar structure only with Parallel.ForEach(new InfinitePartitioner(),...
Thank you for your help.
Use .NET 4.0 Tasks instead of creating new Threads yourself. Tasks give you finer granularity of control, make it easy to pass data into the background operation, and provide excellent support for waiting for results across multiple concurrent tasks and for cancellation of everything in one fell swoop if needed. Highly recommended.
How to run the code within TestingButton_Click on several threads in
background.
I would use a Task as they were design to do exactly what you want.
The only other question I will answer until you get closer to the actual solution is the following:
Report progress
There are lots of ways to report the progress on a given thread, you would have to subscribe to an event, and write code to report the progress of the thread. In order to update a control on the form, this would require you Invoke the change, this is not a trivial feature.

Basic Threading Question

This question has probably been asked in various ways before, but here is what I want to do. I am going to have a Windows form with many tabs. Each tab will contain a grid object. For each tab/grid that is created by the user, I would like a spawn off a dedicated thread to populate the contents of that grid with constantly arriving information. Could anyone provide an example of how to do this safely?
Thanks.
Inside the initialization for the tab (assuming WinForms until I see otherwise):
Thread newThread = new Thread(() =>
{
// Get your data
dataGridView1.Invoke(new Action(() => { /* add data to the grid here */ } );
});
newThread.Start();
That is obviously the most simple example. You could also spawn the threads using the ThreadPool (which is more commonly done in server side applications).
If you're using .NET 4.0 you also have the Task Parallel library which could help as well.
There are two basic approaches you can use. Choose the one that makes the most sense in your situation. Often times there is no right or wrong choice. They can both work equally well in many situations. Each has its own advantages and disadvantages. Oddly the community seems to overlook the pull method too often. I am not sure why that is really. I recently stumbled upon this question in which everyone recommeded the push approach despite it being the perfect situation for the pull method (there was one poor soul who did go against the herd and got downvoted and eventually deleted his answer leaving only me as the lone dissenter).
Push Method
Have the worker thread push the data to the form. You will need to use the ISynchronizeInvoke.Invoke method to accomplish this. The advantage here is that as each data item arrives it will immediately be added to the grid. The disadvantage is that you have to use an expensive marshaling operation and the UI could bog down if the worker thread acquires the data too fast.
void WorkerThread()
{
while (true)
{
object data = GetNewData();
yourForm.Invoke(
(Action)(() =>
{
// Add data to your grid here.
}));
}
}
Pull Method
Have the UI thread pull the data from the worker thread. You will have the worker thread enqueue new data items into a shared queue and the UI thread will dequeue the items periodically. The advantage here is that you can throttle the amount of work each thread is performing independently. The queue is your buffer that will shrink and grow as CPU usage ebbs and flows. It also decouples the logic of the worker thread from the UI thread. The disadvantage is that if your UI thread does not poll fast enough or keep up the worker thread could overrun the queue. And, of course, the data items would not appear in real-time on your grid. However, if you set the System.Windows.Forms.Timer interval short enough that might be not be an issue for you.
private Queue<object> m_Data = new Queue<object>();
private void YourTimer_Tick(object sender, EventArgs args)
{
lock (m_Data)
{
while (m_Data.Count > 0)
{
object data = m_Data.Dequeue();
// Add data to your grid here.
}
}
}
void WorkerThread()
{
while (true)
{
object data = GetNewData();
lock (m_Data)
{
m_Data.Enqueue(data);
}
}
}
You should have an array of threads, to be able to control them
List<Thread> tabs = new List<Thread>();
...
To add a new one, would be like:
tabs.Add( new Thread( new ThreadStart( TabRefreshHandler ) );
//Now starting:
tabs[tabs.Count - 1].Start();
And finally, in the TabRefreshHandler you should check which is the calling thread number and you'll know which is the tab that should be refreshed!

Categories