Threading Basics

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace testThreads { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { } public void countToLots() { for (int i = 0; i < 10000000; i++) { textBox1.Text = "Counting to 10000000, value is " + i + Environment.NewLine; } } public void countToZero() { for (int i = 10000000; i > 0; i--) { textBox2.Text = "Counting to 0, value is " + i + Environment.NewLine; } } private void button1_Click(object sender, EventArgs e) { Thread countUp = new Thread(new ThreadStart(countToLots)); Thread countDown = new Thread(new ThreadStart(countToZero)); countUp.Start(); countDown.Start(); } private void button2_Click(object sender, EventArgs e) { textBox3.Text = "Bobby bob bob " + Environment.NewLine; } } } 

I really need to try and figure it out - I just don't understand the theory of why I get an error message. Can someone help me please?

Work with cross-streams is invalid: The control 'textBox1' is accessible from a thread, other than a thread created on.

+4
source share
3 answers

User interface controls have "thread affinity"; they do not want to be affected by anything other than the user interface flow; which includes read and write properties. The .Text must be done from a user interface thread using either Invoke or BackgroundWorker .

For instance:

 public void countToLots() { for (int i = 0; i < 10000000; i++) { // running on bg thread textBox1.Invoke((MethodInvoker) delegate { // running on UI thread textBox1.Text = "Counting to 10000000, value is " + i + Environment.NewLine; }); // running on bg thread again } } 

But note that this type of thread switching has overhead. You do not have to redirect each iteration - you must (for example) update the user interface every [n] iterations - in the above example, every 10000, for example.

+5
source

You cannot use the method or property of a Form control from a thread other than the thread that created the (called new) control.

To do this, simply do:

  public void countToLots() { for (int i = 0; i < 10000000; i++) { SetText("Counting to 10000000, value is " + i + Environment.NewLine); } } public void SetText(string text) { if (this.textBox1.InvokeRequired()) { Action<string> auxDelegate = SetText; this.BeginInvoke(auxDelegate,text); } else { this.textBox1.Text = text; } } 

What the method does with beginInvoke simply calls the SetText method from the stream that created the control.

+2
source

Well, about the theory underlying the WHY controllers, it has an affinity like UI.

If you programmed long enough, you should remember the days when forms and rapid application development were not the standard. In those days, just pulling control into shape was rare ... everything was done by the old school.

Now windows have an “old school” way of doing things related to defining WindowProc .

WindowProc is a function that is called to process the application message (there was no notification that I say). This function works in the main thread of the program and is responsible for processing each message that the application receives, including paint and updating the user interface.

Currently, all this is mostly automated, so when creating a form, the code responsible for doing all the work is auto-generated, and you don’t need to worry about it ... but it still exists.

Of course, if the thread responsible for drawing the user interface with all its controls is the main thread, you will see how changing things from another thread can disrupt the application itself with the race conditions and so on. In addition, since UI processing is automatically generated, you cannot just use the synchronization mechanisms that you will use with two standard threads, because you only have access to the code in one thread, and not the main windowproc callback.

In a way, what BeginInvoke will do for you, pass a message to the main thread that says that it kindly handles the delegate in its own context when the time is right, thereby delegating execution to the main thread.

+1
source

Source: https://habr.com/ru/post/1339003/


All Articles