RaYell
RaYell

Reputation: 70404

Calling a method when thread terminates

I have a form that starts a thread. Now I want the form to auto-close when this thread terminates.

The only solution I found so far is adding a timer to the form and check if thread is alive on every tick. But I want to know if there is a better way to do that?

Currently my code looks more less like this

partial class SyncForm : Form {
    Thread tr;

    public SyncForm()
    {
        InitializeComponent();
    }

    void SyncForm_Load(object sender, EventArgs e)
    {
        thread = new Thread(new ThreadStart(Synchronize));
        thread.IsBackground = true;
        thread.Start();
        threadTimer.Start();
    }

    void threadTimer_Tick(object sender, EventArgs e)
    {
        if (!thread.IsAlive)
        {
            Close();
        }
    }

    void Synchronize()
    {
        // code here
    }
}

Upvotes: 8

Views: 14456

Answers (6)

Pavel Tupitsyn
Pavel Tupitsyn

Reputation: 8986

Solution for arbitrary thread (e.g. started by some other code), using UnmanagedThreadUtils package:

// Use static field to make sure that delegate is alive.
private static readonly UnmanagedThread.ThreadExitCallback ThreadExitCallbackDelegate = OnThreadExit;

public static void Main()
{
    var threadExitCallbackDelegatePtr = Marshal.GetFunctionPointerForDelegate(ThreadExitCallbackDelegate);
    var callbackId = UnmanagedThread.SetThreadExitCallback(threadExitCallbackDelegatePtr);

    for (var i = 1; i <= ThreadCount; i++)
    {
        var threadLocalVal = i;

        var thread = new Thread(_ =>
        {
            Console.WriteLine($"Managed thread #{threadLocalVal} started.");
            UnmanagedThread.EnableCurrentThreadExitEvent(callbackId, new IntPtr(threadLocalVal));
        });

        thread.Start();
    }

    UnmanagedThread.RemoveThreadExitCallback(callbackId);
}

private static void OnThreadExit(IntPtr data)
{
    Console.WriteLine($"Unmanaged thread #{data.ToInt64()} is exiting.");
}

Upvotes: 0

Philippe Leybaert
Philippe Leybaert

Reputation: 171734

At the end of your thread method, you can call Close() using the Invoke() method (because most WinForms methods should be called from the UI thread):

public void Synchronize()
{
   Invoke(new MethodInvoker(Close));
}

Upvotes: 1

Lloyd Powell
Lloyd Powell

Reputation: 18760

If you have a look at a BackgroundWorker, there is a RunWorkerCompleted event that is called when the worker completes.

For more info on BackgroundWorkers Click Here

Or

You could add a call to a complete function from the Thread once it has finished, and invoke it.

void Synchronize()
{
    //DoWork();
    //FinishedWork();
}

void FinishedWork()
{
if (InvokeRequired == true)
  {
  //Invoke
  }
else
  {
  //Close
  }
}

Upvotes: 6

Adriaan Stander
Adriaan Stander

Reputation: 166326

Have a look at delegates, IAsyncResult, BeginInvoke and AsyncCallback

Upvotes: 1

Sam Harwell
Sam Harwell

Reputation: 99859

Edit to make it call a helper method so it's cleaner.

thread = new Thread(() => { Synchronize(); OnWorkComplete(); });

...

private void OnWorkComplete()
{
    Close();
}

Upvotes: 6

Steve Gilham
Steve Gilham

Reputation: 11277

The BackgroundWorker class exists for this sort of thread management to save you having to roll your own; it offers a RunWorkerCompleted event which you can just listen for.

Upvotes: 12

Related Questions