Maik Klein
Maik Klein

Reputation: 16148

Starting a new thread with a constructor

I finished my little project that does some heavy lifting. i realized in this short calculation time, my GUI freezes. So I did some research and I found this => http://www.codeproject.com/Articles/4381/Threading-out-tasks-in-a-C-NET-GUI

I started to implement this is my project, but i realized that this particular implementation does not work in my project.

In my project i have many classes and one " manager " that controls all other classes. If i initilize this Manager class , it already does the heavy lifting in the constructor.

To my Question :

How do i start a new thread with a contructor ?

private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)
        {


            if (System.IO.File.Exists(e.FullPath) == true)
            {

                Manager mgr = new Manager(e, handreader); // here starts the heavy lifting
                Thread mgrThread = new Thread(new ThreadStart(mgr));  // what to do ?
                sl.Text = mgr.test();
                txtLog.Text = mgr.output();


            }
        }

EDIT : okay i decided to recode my program. now the heavy lifting is in one function but i think i made a mistake.

the whole program looks like this :

 private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)
        {


            if (System.IO.File.Exists(e.FullPath) == true)
            {
                Manager mgr = new Manager(e, handreader, txtLog, sl);
                //sl.Invoke(new MethodInvoker(mgr.test));
                sl.Invoke(new MethodInvoker(mgr.test)); // first try 
                Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try

            }
        }

the sl.Invoke(new MethodInvoker(mgr.test)); // first try works but it still freezes my GUI.

Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try

and this line does nothing.

my test function :

 public void test()
    {
        StringBuilder builder = new StringBuilder();
        foreach (PlayerController pc in fm.lPc)
        {
          Range  range = new Range(handReader.hand, handReader.handversus, pc);
          builder.Append(pc.getHeroCardsSimple()+" vs 100% range =   "+range.vsRange()+"\r\n");
        }
        sl.Text = builder.ToString();
    }

Upvotes: 3

Views: 4924

Answers (3)

Christoph Fink
Christoph Fink

Reputation: 23093

Move the "heavy lifting" out of the constructor to some kind of "worker" and run that method in the thread.

Change the Manager from:

public Manager(/*params*/)
{
    //params
    //heavy lifting
}

to

public Manager(/*params*/)
{
    //params
}

public void DoWork()
{
    //heavy lifting
}

and the calling to

Manager mgr = new Manager(e, handreader);
Thread mgrThread = new Thread(new ThreadStart(mgr.DoWork));
mgrThread.Start();

ATTENTION: If you access/change UI elements in the thread, don't forget to Invoke that calls!

Upvotes: 2

Bas
Bas

Reputation: 27085

You should use a different approach for this. Your constructor is still being invoked on the GUI thread.

   

    Func<Manager> asyncConstructor;
    private void fileSystemWatcher1_Changed(object sender, System.IO.FileSystemEventArgs e)
    {
        asyncConstructor = new Func<Manager>(() => new Manager());

        asyncConstructor.BeginInvoke(ManagerConstructed, null);
    }

    private void ManagerConstructed(IAsyncResult result)
    {
        Manager mgr = asyncConstructor.EndInvoke(result);
        //we can only access form controls from the GUI thread, 
        //if we are not on the gui thread then
        //do the changes on the gui thread.
        if (this.InvokeRequired)
        {
            this.Invoke(new Action(() =>
            {
                sl.Text = mgr.test();
                txtLog.Text = mgr.output();
            }));
        }
    }

Upvotes: 3

Jon Skeet
Jon Skeet

Reputation: 1499800

Well, you could use:

Thread mgrThread = new Thread(() => new Manager(e, handreader));

... but then you won't have a reference to the manager for the rest of your code.

To be honest, doing the heavy lifting in the constructor is generally a bad idea anyway, for various reasons. It would be better to move that work somewhere else:

// Constructor just sets things up
Manager mgr = new Manager(e, handreader);
// DoWork method does the real work
Thread mgrThread = new Thread(mgr.DoWork);

Upvotes: 1

Related Questions