Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
410 views
in Technique[技术] by (71.8m points)

c# - How to ensure that async method finished work?

I'm very new to threads, so my thoughts and questions might be a bit silly :)

I fill WinForm control with data from another thread, so I have to call Invoke() when I'm trying to access control.

If I understand correctly, treeView.BeginInvoke(/*some Action()*/) makes this Action<>() run in main thread. But I "fire and forget" this BeginInvoke(), so I can't know when the work is actually done. And even when worker thread closes and execution returns to main thread, I can't be sure that all BeginInvoke() methods have finished execution.

That's why even after returning to main thread I can't manage with Control to which I fired BeginInvoke().

The actual problem is TreeView.ExpandAll() doesn't work.

Take a look at the code snippet below.

private void btnGetTree_Click(object sender, EventArgs e) {
    var treeViewWriter = new Thread(() => UpdateTreeView(new AddXmlNodeArgs(di, null), treeDirectoryContents));
    treeViewWriter.Start();
    treeViewWriter.Join();
    treeDirectoryContents.ExpandAll();
}

// method runs on a worker thread
public static void UpdateTreeView(AddXmlNodeArgs args, TreeView treeView) {
    // I will miss details... Here is the code that I run for every new TreeNode:
    treeView.UpdateTree((TreeView tree) => {
        tree.Nodes[0].Nodes.Add(newTreeNode); // treeView.Nodes[0]...
    });
}

// Extension method for TreeView
public static void UpdateTree(this TreeView tree, Action<TreeView> code) {
    if (tree.InvokeRequired)
        tree.BeginInvoke(code, tree);
    else
        code.Invoke(tree);
}

I fire tree.BeginInvoke() but I don't call EndInvoke() anywhere. So I guess when in btnGetTree_Click execution reaches to treeDirectoryContents.ExpandAll() - not all Invoke() methods have finished their work. Thats why .ExpandAll() doesn't work.

Correct me if I'm wrong, and please give an advice how to solve this problem.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is absolutely wrong:

treeViewWriter.Start();
treeViewWriter.Join();

Never call Thread.Join from Main Thread! because that Join freezes the application and all those BeginInvoke/Invoke never gets fully executed because the message is not handled.

This is how BeginInvoke() actually works:

  1. It sends some WM_USER (or the like) on message loop.
  2. Main thread pops this message in Application.DoEvents() (or the like which is always called in Application.Run())
  3. Main thread executes the delegate passed to BeginInvoke()
  4. Main thread signals end of execution (by WaitHandle in IAsyncResult)
  5. EndInvoke() waits for such signal (or if IAsyncResult from BeginInvoke is never stored, it gets garbage-collected)

So again: you eiter write it purely event-driven or do something like this:

private bool done = false;
void click(object, EventArgs) {
    thread.Start();
    while(!done) Application.DoEvents();
    tree.ExpandAll();
}

ADDON: Eihter use Invoke() (synchronized) and the above loop with Application.DoEvents()
or use BeginInvoke() and call your ExpandAll the same way (through BeginInvoke() from the thread)

ADDON2:

private bool done;
void click(object,EventArgs) {
    done = false; // init state
    new Thread(work).Start(); // start backgound work
    while(!done) Application.DoEvents(); // wait until done
    finish(); } // finish the job in main thread
void work() {
    Thread.Sleep(100); // do your work
    done = true; } // signal done
void finish() {
    whatever(); } // called on main thread

void click2(object,EventArgs) {
    new Thread(work2).Start(); } // just start the hread
void work2() {
    Thread.Sleep(100); // do your work
    BeginInvoke(new Action(finish)); } // execute finish() on main thread

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...