【问题标题】:Task (or thread) requires Wait or Join to work任务(或线程)需要等待或加入才能工作
【发布时间】:2010-12-05 12:39:32
【问题描述】:

我正在尝试制作一个插件类型系统。过去,我在这些方面做了一些事情,所有插件都在主线程中执行,如果插件花费很长时间,这会导致问题。所以我想我会使用 Tasks 在每个插件中执行适当的方法。

我有一个主程序,它使用 Assembly.LoadFile 加载每个插件,然后对用户键入的命令做出反应。如果这些命令之一由插件处理(插件报告它们处理什么命令,主程序在加载它们时询问),我的程序将在其自己的任务中启动插件中的方法。

Task t = Task.Factory.StartNew(() => Plugin.ProcessCommand(cmd, Params, Context));

每个插件还实现了一个事件,当它有数据要发送到主程序进行输出时使用。主程序在加载每个插件时都会为该事件附加一个处理程序。

插件的 ProcessCommand 方法做任何需要的工作,触发 OnOutput 事件,然后结束。

这是一个非常简单的插件:

public override void ProcessCommand(PluginCommand Command, PluginParameters Parameters, PluginContext Context)
{
    OnOutputGenerated(this,"Hello from Plugin A");
}

这适用于我制作的第一个插件。所以我创建了另一个,使用完全相同的代码,只是将“Hello from Plugin A”更改为“Hello from Plugin B”。

插件 A 始终有效。如果我在主程序中发出适当的命令,它会运行并从插件 A 中说 Hello。太好了。

问题是:插件 B 可能每 30 次尝试执行一次。但是,我发现如果按以下方式调用插件,它每次都能正常工作:

Task t = Task.Factory.StartNew(() => Plugin.ProcessCommand(cmd, Params, Context));
t.Wait(100);

这是否有技术原因可能会有所帮助?我已经阅读了几乎所有的 http://www.albahari.com/threading/ 试图弄清楚事情,但我没有任何运气。

值得注意的是,我也使用线程完成了此操作,但存在同样的问题。

Thread t = new Thread(() => Plugin.ProcessCommand(cmd, Params, Context));
t.Start();

添加:

t.Join(100);

“修复”它。

更新

我已经简化了一切。我做了一个新项目,去掉了所有与 bug 无关的代码。

foreach (string File in Directory.GetFiles(PluginDir, "*.dll")) {

    try {

        IPlugin Plugin = PluginManager.LoadPlugin(File);
        Plugin.OnOutputGenerated += new PluginOutputEvent(Plugin_OnOutputGenerated);

    } catch (Exception ex) {

    }

}

// main loop

string Line = Console.ReadLine();

foreach (IPlugin Plugin in PluginManager.LoadedPlugins) {

    foreach (PluginCommand cmd in Plugin.GetCommands()) {

        if (cmd.Command.Equals(Line, StringComparison.InvariantCultureIgnoreCase)) {

            PluginParameters Params = cmd.TryParseParameters(ParamString);
            Task t = Task.Factory.StartNew(() => Plugin.ProcessCommand(cmd, Params, Context));

        }

    }

}

// output handler

static void Plugin_OnOutputGenerated(IPlugin Plugin, string OutputString) {

    Console.WriteLine("Output: " + OutputString);

}

主要问题已经改变。以前,其中一个插件大部分时间都不起作用。想象一下两个插件。

插件 A
* 有一个命令:CommandA
* 命令使用字符串“Hello from Plugin A”触发 OnOutputGenerated 事件

插件 B
* 有一个命令:CommandB
* 命令使用字符串“Hello from Plugin B”触发 OnOutputGenerated 事件

如果我运行我创建的这个新项目,并发出命令“CommandA”,它将返回“Hello from Plugin B”。它会继续这样做,直到我真正发出“CommandB”。完成此操作后,它会打印“来自插件 B 的 Hello”(应该如此)。如果我再次发出“CommandA”,它会返回“Hello from Plugin A”(就像它最初应该有的那样)。

如果我添加

t.Wait(100);

它是固定的。它似乎仍然以某种方式与任务有关,但我不知道如何解释。看来我的逻辑是好的。当它应该执行插件 A 时,我看不到它会如何执行插件 B,反之亦然。

【问题讨论】:

  • 会不会是你的任务变量 t 在完成之前就超出了范围?

标签: c# multithreading plugins c#-4.0 task


【解决方案1】:

听起来好像没有WaitJoin,您的主程序只是在请求的Task 代码有机会运行之前退出。如果 Task 逻辑曾经内联在主线程中,那将意味着主线程将在代码执行时等待。现在您已将其移至单独的线程,您必须添加显式等待以允许您启动的每个Task 完成(可能会超时,以防出现问题)。

即使您不等待,Task 也可能偶尔完成 - 这将是不确定的,具体取决于任何个人运行的时间。

您能否澄清没有WaitJoin 时主线程中会发生什么?

【讨论】:

  • 出于所有意图和目的,主程序是一个带有 Console.ReadLine() 的大循环,一个解析输入内容的部分,然后是在用户输入内容时调用插件的部分适合插件。其目的是允许用户触发许多可能耗时的任务,而无需等待程序再次访问 Console.ReadLine。
  • 谢谢 - 当您不等待/加入时,您的完成事件处理程序是否会超出 cmets 中 @Jakob 所指出的范围?
  • 现阶段真的不确定。它看起来不像,但我正在尝试各种事情。当我自己弄清楚到底发生了什么时,我会提供更多代码!目前大约有三个不同的错误。我正在尝试找出哪些是真正相关的。
猜你喜欢
  • 1970-01-01
  • 2013-07-15
  • 1970-01-01
  • 1970-01-01
  • 2021-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-17
相关资源
最近更新 更多