c# - 任务(或线程)需要 Wait 或 Join 才能工作

标签 c# multithreading plugins c#-4.0 task

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

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

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

“修复”它。

已更新

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

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”。完成后,它会打印“Hello from Plugin B”(它应该如此)。如果我随后再次发出“CommandA”,它会返回“Hello from Plugin A”(正如它最初应该返回的那样)。

如果我添加

t.Wait(100);

它是固定的。它似乎仍然以某种方式与任务相关,但我无法解释如何。否则我的逻辑似乎没问题。我看不出它如何在应该执行插件 A 时执行插件 B,反之亦然。

最佳答案

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

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

您能否阐明在没有 WaitJoin 的情况下主线程中发生了什么?

关于c# - 任务(或线程)需要 Wait 或 Join 才能工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4358816/

相关文章:

javascript - 使用颜色选择器手动更改单元格/行/列的颜色?

jquery - 寻找一个可以模糊/隐藏文本的 jQuery 插件

c# - 加密 SQL 连接字符串

c# - 字符串常量在编译后的 DLL 中占用多少空间?

c# - 在 Xamarin.Forms Device.BeginInvokeOnMainThread() 中不显示来自通知回调的消息框*仅*在物理设备上的发布配置中

multithreading - 识别嵌入式软件设计中的线程

c# - foreach 语句不能对类型为 'object' 的变量进行操作

multithreading - Ocaml : Thread. 延迟未按预期工作

java - 如何演示 Java 指令重新排序问题?

android - 如何在应用程序自动注销时收到通知并在关闭时清理数据