Multithreaded calls in a Windows Forms application?

I am trying to make my C # application multithreaded because sometimes I get an exception that says I made a call to the thread in an unsafe way. I have never done multithreading before in a program, so bear with me if I seem a little ignorant about this problem.

An overview of my program is that I want to make a performance monitoring application. This implies using the performance and performance class in C # to start and monitor application processor time and send that number back to the user interface. However, in a method that actually calls the nextValue method of the performance counter (which is set to execute every second thanks to a timer), sometimes I get the above exception, which would say that the thread was called in an unsafe way.

I have attached the code for your reading. I know this is a rather time-consuming issue, so I would be very grateful if someone could help me on where to create a new thread and how to safely call it. I tried to take a look at what was on MSDN, but it just bothered me.

private void runBtn_Click(object sender, EventArgs e) { // this is called when the user tells the program to launch the desired program and // monitor it CPU usage. // sets up the process and performance counter m.runAndMonitorApplication(); // Create a new timer that runs every second, and gets CPU readings. crntTimer = new System.Timers.Timer(); crntTimer.Interval = 1000; crntTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); crntTimer.Enabled = true; } private void OnTimedEvent(object source, ElapsedEventArgs e) { // get the current processor time reading float cpuReading = m.getCPUValue(); // update the current cpu label crntreadingslbl.Text = cpuReading.ToString(); // } // runs the application public void runAndMonitorApplication() { p = new Process(); p.StartInfo.UseShellExecute = true; p.StartInfo.CreateNoWindow = true; p.StartInfo.FileName = fileName; p.Start(); pc = new System.Diagnostics.PerformanceCounter("Process", "% Processor Time", p.ProcessName, true); } // This returns the current percentage of CPU utilization for the process public float getCPUValue() { float usage = pc.NextValue(); return usage; } 
+6
multithreading c # process winforms performancecounter
source share
3 answers

Check out John Skeet's article on multithreading, especially the multithreaded winforms page. He must correct you.

Basically you need to check if a call is required and then make a call if necessary. After reading the article, you can reorganize your UI update code into blocks that look like this:

 private void OnTimedEvent(object source, ElapsedEventArgs e) { // get the current processor time reading float cpuReading = m.getCPUValue(); if (InvokeRequired) { // We're not in the UI thread, so we need to call BeginInvoke BeginInvoke(new Action(() => crntreadingslbl.Text = cpuReading.ToString())); return; } // Must be on the UI thread if we've got this far crntreadingslbl.Text = cpuReading.ToString(); } 

A request is called in your code because you are using a timer. According to the documentation for System.Timers.Timer :

An expired event occurs in the ThreadPool thread.

This means that the OnTimedEvent () method that you set as the Timer delegate will execute in the next available ThreadPool thread, which will definitely not be your UI thread. The documentation also suggests an alternative way to solve this problem:

If you use a timer with a user interface element, such as a form or control, assign a form or control that contains a SynchronizingObject timer, so that the event is marshaled to the user interface stream.

You may find this route easier, but I have not tried it.

+7
source share

Your problem, I think, is this line:

 crntreadingslbl.Text = cpuReading.ToString(); 

Runs outside the user interface thread. You cannot update the user interface element outside the user interface stream. You need to invoke Invoke in the window to invoke the new method in the user interface thread.

All that said, why not use perftones? It is built on purpose.

0
source share

The BackGroundWorker component can help you. It is available on the toolbar, so you can drag it into your form.

This component provides a set of events for performing tasks in a thread other than a user interface thread. You do not need to worry about creating a thread.

All interaction between code running in the background and user interface controls must be handled by event handlers.

For your scenario, you can set a timer to start the background worker at a specific interval.

 private void OnTimedEvent(object source, ElapsedEventArgs e) { backgroundWorker.RunWorkerAsync(); } 

Then you implement the proper event handlers for actually collecting data and updating the user interface

 private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { // Collect performance data and update the UI } 
0
source share

All Articles