0

I've been looking at https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-make-thread-safe-calls-to-windows-forms-controls and other Stack Overflow questions for a good long while now to figure out how to use thread-safe methods to access a ListView controls from different threads.

Here's how I want to implement parallel tasks in my program: I call four different methods in parallel with:

Parallel.Invoke(ProcessLow, ProcessMed, ProcessHigh, ProcessSprint);

Each method searches through the same collection (data[i].Knots) with a for loop and looks for a different range of values within that collection, then if one of the methods finds an appropriate value within the range it's looking for it adds the time and knots (data[i].Time, data[i].Knots) to its respective ListView (the methods write to lstvLow, lstvMed, lstvHigh and lstvSprint respectively). At the moment it's just throwing the exception for non-thread safe code. Also will it break if I have different threads just reading off the same collection? (if so, how can I work around this?)

tldr: Parallel processing is new to me, how do I make a thread-safe call to a windows form control.
And also if you can, point me in the direction of some good reading other than msdn for Parallel tasking.

edit: this is with winforms

dymanoid
  • 14,771
  • 4
  • 36
  • 64
Matt Wilson
  • 23
  • 1
  • 6

2 Answers2

1

To make thread safe call. use Control.Invoke(); method. Assuming you have instance of ListView mylistView; you can write:

object result =  mylistView.Invoke(new Action(() => mylistView.DoSomething()));
Dzliera
  • 646
  • 5
  • 15
0

As I understand, you are new to multitasking. I hope my case study will help you. Create a windows form with next controls:

  • startButton, stopButton as Button
  • minTextEdit, maxTextEdit as TextEdit
  • listListView as ListView

For startButton and stopButton use the appropriate methods: startButton_Click and stopButton_Click.

Full the code below:

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Thread0
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private static readonly Random _random = new Random();
        private List<int> lst = new List<int>();
        private bool isRun = false;

        private void startButton_Click(object sender, EventArgs e)
        {
            isRun = true;
            stopButton.Enabled = true;
            startButton.Enabled = false;
            var tskMain = Task.Run(() =>
            {
                for (int i = 0; i < 8; i++)
                {
                    var tsk1 = Task.Run(() =>
                    {
                        while (true)
                        {
                            int max = 0;
                            int min = Int32.MaxValue;
                            lock (lst)
                            {
                                int num = _random.Next(1, 1000000);
                                lst.Add(num);
                                foreach (var x in lst)
                                {
                                    if (x > max) max = x;
                                    if (min > x) min = x;
                                }
                                listListView.BeginInvoke(new Action(() => listListView.Items.Insert(0, num.ToString())));
                            }
                            maxTextBox.BeginInvoke(new Action(() => maxTextBox.Text = max.ToString()));
                            minTextBox.BeginInvoke(new Action(() => minTextBox.Text = min.ToString()));

                            if (!isRun) break;

                            Thread.Sleep(100);
                        }
                    });
                }
            });
        }

        private void stopButton_Click(object sender, EventArgs e)
        {
            isRun = false;
            stopButton.Enabled = false;
            startButton.Enabled = true;
        }
    }
}

When you click on the Start button, the stream create and run tskMain thread, which creates 8 more threads. In each of them, an integer is added to the list of values lst, and the search for the maximum and minimum values. The new number is also added to the listListView, and the maximum and minimum value in the corresponding minTextEdit and maxTextEdit.

For work it is convenient to use lambda expression.

lock(lst) ... blocks work with the list of values. One action per time, so that there are no exceptions.

And the BeginInvoke method allows you to call methods from threads for form elements that are in the main form stream. The Action is used to "transform" the lambda expression into a delegate method.

Inside each thread, the variable IsRun is checked, if its value becomes false, the thread execution stops.

Well, to ensure that everything is not very quickly use .Sleep

Quazer
  • 353
  • 1
  • 8