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

发布于 2024-10-06 06:33:34 字数 2926 浏览 0 评论 0原文

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

我有一个主程序,它使用 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);

“修复”它。

更新

我简化了一切。我创建了一个新项目,删除了所有与错误无关的代码。

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”触发 OnOutputGenerate 事件

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

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

如果我添加

t.Wait(100);

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

I am trying to make a plugin type system. I have made something along these lines in the past where all plugins execute in the main thread, which leads to problems if the plugins are taking a long time. So I thought I'd execute the appropriate methods in each plugin using Tasks.

I have a main program, which loads each plugin using Assembly.LoadFile, and then reacts to commands a user types. If one of these commands is handled by a plugin (the plugins report what commands they handle, the main program asks when it loads them), my program will start a method in the plugin in its own Task.

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

Each plugin also implements an event used when it has data to send to the main program for output. The main program attaches a handler to this event when it loads each plugin.

The plugin's ProcessCommand method does whatever work is needed, triggers the OnOutput event, and then ends.

This is a very simple plugin:

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

This worked fine with the first plugin I made. So I created another, using the exact same code, just changing "Hello from Plugin A" to "Hello from Plugin B."

Plugin A always works. If I issue the appropriate command in the main program, it runs and says Hello from Plugin A. Great.

The problem is: Plugin B executes maybe one in every 30 attempts. I've discovered, however, that if call the plugin in the following way, it works every time:

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

Is there a technical reason why this might help? I've read through pretty much all of http://www.albahari.com/threading/ trying to figure things out, but I've not had any luck.

It's worth noting that I've also done this with threads, with the same problem.

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

Adding:

t.Join(100);

"fixed" it.

Updated

I've simplified everything. I've made a new project, which strips out all the code unrelated to the bugs.

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

}

The main issue has changed. Previously, one of the plugins didn't work most of the time. Imagine two plugins.

Plugin A
* Has one command: CommandA
* Command triggers OnOutputGenerated event with the string "Hello from Plugin A"

Plugin B
* Has one command: CommandB
* Command triggers OnOutputGenerated event with the string "Hello from Plugin B"

If I run this new project I've made, and issue the command "CommandA", it will return "Hello from Plugin B". It continues doing this until I actually issue "CommandB". Once I've done that, it prints "Hello from Plugin B" (as it should). If I then issue "CommandA" again, it returns "Hello from Plugin A" (as it should have originally).

If I add

t.Wait(100);

it's fixed. It still seems to be related to the Task somehow, but I'm at a loss to explain how. It would appear that my logic otherwise is fine. I can't see how it would execute Plugin B when it should execute Plugin A, or vice-versa.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

苦行僧 2024-10-13 06:33:34

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

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

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

It sounds like without the Wait or Join, your main program simply exits before the requested Task code has a chance to run. If the Task logic used to be inline in the main thread, that would have implied the main thread would wait while the code executed. Now you have moved it to a separate thread, you have to add an explicit wait to allow every Task you start up to complete (maybe with a timeout, in case something goes wrong).

It's possible that even if you don't wait, a Task could occasionally finish up - that's going to be indeterminate, depending on the timing in any individual run.

Can you clarify what happens in the main thread without the Wait or Join?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文