本文介绍了如何保证异步方法完成工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很新的线程,所以我的想法和问题,可能会有点傻了:)

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

我填写的WinForm 控制从另一个线程的数据,所以我必须调用的invoke()时,我米试图访问控制。

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

如果我理解正确的话, treeView.BeginInvoke(/ *一些行动()* /)使这个动作<>()在主线程中运行。但我射后不理这个的BeginInvoke(),所以我不知道什么时候工作实际完成的。甚至当工作线程关闭,并执行返回到主线程,我不能肯定所有的的BeginInvoke()方法已经执行完毕。

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.

这就是为什么即使是回到主线程后,我无法与控制来我解雇管理的BeginInvoke()

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

的实际问题 TreeView.ExpandAll()不起作用。

看看下面的code段。

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);
}

我火 tree.BeginInvoke(),但我不叫 EndInvoke会()的任何地方。所以我在想,当 btnGetTree_Click 执行达到 treeDirectoryContents.ExpandAll() - 不是所有的调用()方法已经完成了他们的工作。这就是为什么 .ExpandAll()无法正常工作

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.

推荐答案

这是绝对错误的:

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

切勿从主线程中调用的Thread.join!,因为加入响应的应用程​​序和所有那些的BeginInvoke / 调用从来没有得到完全执行,因为没有被处理的消息。

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.

这是怎么的BeginInvoke()的实际工作:

  1. 在它发送一些WM_USER(或类似)的消息循环。
  2. 在主线程中弹出 Application.DoEvents该邮件()(或类似它总是叫 Application.Run()
  3. 在主线程执行传递给委托的BeginInvoke()
  4. 执行主线程信号端(由的WaitHandle 的IAsyncResult
  5. EndInvoke会()等待这样的信号(或者,如果的IAsyncResult 的BeginInvoke 不会存储,它得到垃圾收集)
  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)

所以,再一次:你eiter写纯粹的事件驱动或做这样的事情:

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使用的invoke()(同​​步)和 Application.DoEvents()上面的循环
或者使用的BeginInvoke(),并致电ExpandAll以同样的方式(通过的BeginInvoke()从线程)

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

这篇关于如何保证异步方法完成工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 17:06