任务(或线程)需要等待或加入才能工作

时间:2010-12-05 12:39:33

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

我正在尝试制作插件类型系统。在过去,我已经在主线程中执行了所有插件执行的操作,如果插件需要很长时间,则会导致问题。所以我想我会使用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
*命令触发OnOutputGenerated事件,字符串为“Hello from Plugin A”

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

如果我运行这个新项目,并发出命令“CommandA”,它将返回“Hello from Plugin B”。它继续这样做,直到我实际发出“CommandB”。一旦我完成了它,就打印出“插件B的Hello”(应该如此)。如果我再次发出“CommandA”,它将返回“插件A中的Hello”(原本应该是这样)。

如果我添加

t.Wait(100);

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

1 个答案:

答案 0 :(得分:2)

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

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

您是否可以在没有WaitJoin的情况下澄清主线程中发生的情况?