1

Hi I'm new to multithreading and TPL - testing Task call and writing the status back to text box on Main UI and didn't get the expected result. I'm testing this feature because I need to implement the tool for my work. My program will loop to create 30 tasks and start and showing which task are processing in Text box. I pass "i" counter into DoWork fuction and display that "i" counter. My Code as below

private void DoWork(object state)
       {
           object[] obj = state as object[];
           int i = Convert.ToInt32(obj[0]);

           
           Invoke(new MethodInvoker(delegate()
           {

               richTextBox1.Text += "Testing" + i.ToString() + "\n";

           }));
       }

       private void btnTest_Click(object sender, EventArgs e)
       {
           for (int i = 0; i < 30; i++)
           {
               Task t1 = new Task(() => DoWork(new object[] {i}) );            
               t1.Start();

           }
       }

I'm expecting 1 to 30 display in text box in random order but it display like this. I have attached the image as well as display in here. enter image description here

the result seems odd and mostly displaying like below (almost all display 30). "i" is parameter passing to "DoWork" as object.

Testing0 Testing3 Testing12 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30 Testing30

Your help to make me understand and figure out to fix this issue is greatly appreciated.

Regards William

Williams
  • 11
  • 1
  • 1
    change `private void btnTest_Click...` to `private async void btnTest_Click...`. Then change `Task t1 = new Task(() => DoWork(new object[] {i}) ); ` to `await Task.Run(() => DoWork(new object[] {i}) ); `. You really should [read up on](https://blog.stephencleary.com/2012/02/async-and-await.html) the basics asnyc/await programming. – Andy Apr 19 '21 at 13:55
  • Thank you @Andy. I will read that up – Williams Apr 19 '21 at 14:02
  • You probably should use `BeginInvoke` or `InvokeAsync` since `Invoke` can lead to a GUI thread deadlock. –  Apr 19 '21 at 14:05

1 Answers1

1

The main problem is probably that you use a changing variable in your delegate.

Change the code to to

var tmp = i;
Task t1 = new Task(() => DoWork(new object[] { tmp }) );   

I would also recommend you you simply the code a bit, i.e.

private void DoWork(int i)

and

var tmp = i;
Task.Run(() => DoWork(tmp));

Note that I'm not sure what you would expect this example to demonstrate. You are essentially scheduling a bunch of tasks on the threadpool, and the only thing the tasks do is schedule new tasks back to the main thread. While the output might be somewhat arbitrary, it will probably have a low level of randomness.

Another good practice is to always handle the result of tasks. If you just start a task you will have no way of knowing if it failed with an exception, and this might hide bugs in your program.

JonasH
  • 28,608
  • 2
  • 10
  • 23