2

I try to call a function after thread finished but I can't . I only can use while(threadName.isAlive) method before my function caller code , but it's not good because the program stops when i use this code . have you any idea ?

public partial class Form1 : Form
{
    Thread myThread;
    string myString = string.Empty;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        myThread = new Thread(write);
        myThread.Start();
        while (myThread.IsAlive) ;
        textBox1.Text = myString; 
    }

    public void write()
    {
        for (int i = 0; i < 10; i++) {

            myString += "aaa " + i + "\r\n";
            Thread.Sleep(1000);
        }
    }
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
amir mehr
  • 75
  • 1
  • 9
  • 3
    Please add your code – Backs Jul 20 '18 at 08:39
  • 8
    It seems you want a `Task`, not `Thread`: `myTask.ContinueWith(...)` – Dmitry Bychenko Jul 20 '18 at 08:40
  • 3
    Possible duplicate of [Notify when thread is complete, without locking calling thread](https://stackoverflow.com/questions/19048492/notify-when-thread-is-complete-without-locking-calling-thread) – Biesi Jul 20 '18 at 08:40
  • If all you want to do is set the textbox text - this can be done on the thread when you exit the for loop. See this : https://stackoverflow.com/questions/1136399/how-to-update-textbox-on-gui-from-another-thread – PaulF Jul 20 '18 at 08:52
  • 1
    `Thread` focusses a lot on mechanism. You *could* create a `Task`, as others have said, and that is more modern, or you could pull yourself fully up to date and embrace `async`/`await`. Do that and you may even be able to interact with UI directly at the appropriate times (if `Thread.Sleep` becomes `Task.Delay` and represents *I/O* work rather than *CPU* work) – Damien_The_Unbeliever Jul 20 '18 at 08:53
  • 1
    The first thing to learn is that you should (almost) never use a Thread. Use Tasks and async/await. – bommelding Jul 20 '18 at 09:41

2 Answers2

7

If you must attach to a Thread rather than a Task then you can just start a task to wait for the thread to exit and then run some additional code, like this:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    static class Program
    {
        static void Main()
        {
            Thread thread = new Thread(work);
            thread.Start();

            Task.Run(() =>
            {
                thread.Join();
                Console.WriteLine("Run after thread finished");
            });

            Console.ReadLine();
        }

        static void work()
        {
            Console.WriteLine("Starting work");
            Thread.Sleep(1000);
            Console.WriteLine("Finished work");
        }
    }
}

However, the modern way to approach this is to use Task, await and async.

For example:

async void button1_Click(object sender, EventArgs e)
{
    textBox1.Text = "Awaiting task";
    await writeAsync();
    textBox1.Text = "Task finished";
}

Task writeAsync()
{
    return Task.Run(() => write());
}

void write()
{
    Thread.Sleep(10000);
}

If you try this second approach, you'll see that the UI remains responsive while the textbox says "Awaiting task".

Also note that normally you'd want to stop the user from being able to press the button again while the task is being awaited, to avoid multiple tasks being run. The easiest way to do that is to disable the button while the task is active like so:

async void button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false;

    textBox1.Text = "Awaiting task";
    await writeAsync();
    textBox1.Text = "Task finished";

    button1.Enabled = true;
}
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • I just want to learn . I use this code and I want to use textbox instead of console.writeline . but it gives me this error -> An exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll but was not handled in user code Additional information: Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on. – amir mehr Jul 20 '18 at 08:55
  • 1
    @amirmehr If you see my second example, it shows you how to do this. However, note that you need .Net 4.5 or later (I think) to do it this way. – Matthew Watson Jul 20 '18 at 08:57
3

Switch to Task from Thread and let .Net do the (low level) work for you:

public async Task<string> write() {
  string myString = string.Empty;

  for (int i = 0; i < 10; i++) {
    myString += "aaa " + i + "\r\n";

    await Task.Delay(1000);
  }

  return myString;
}

private async void button1_Click(object sender, EventArgs e) {
  string result = await write();    

  // continue with (please, notice await) with assigning
  textBox1.Text = result; 
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215