gpt4 book ai didi

c# - 如何在 C# 中执行 "interrupt"的 while 循环并返回到同一位置(不使用任何线程)

转载 作者:行者123 更新时间:2023-11-30 21:53:22 28 4
gpt4 key购买 nike

我需要帮助在 while 循环之间切换并恢复到它们所在的确切状态。

一个例子是这样的:

while(1==1) 
{
x++;
x++;
x++;
x++;
}

while(1==1)
{
Console.WriteLine("X=" + x);
Console.WriteLine("X=" + x);
Console.WriteLine("X=" + x);
Console.WriteLine("X=" + x);
}

我正在为一个允许您使用 C# 创建操作系统的项目工作。它叫做 Cosmos,用谷歌快速搜索应该可以找到一些信息。

我需要做的是暂停其中一个循环,然后恢复(或开始)一个不同的循环,直到时间结束,然后该循环将被暂停,另一个循环将被恢复等等无限循环循环。

我正在尝试制作一个简单的任务调度程序,并且我计划进行比简单的 while 循环切换更多的更改,但我希望将其作为原始状态并用于测试。

因此,需要发生的是第一个 while 循环执行,然后暂停并执行第二个。需要发生的是每个循环都会暂停并切换到不同的循环,实际上看起来好像它们在同时运行。所以,会发生的是 x 会增加,然后被打印,x 增加,等等。

最佳答案

好吧,我们可以通过创建状态机来处理每个循环来进行协作(非抢占式)多任务处理:

private interface IStateMachine
{
void DoNext();
}

private class Loop0 : IStateMachine
{
private int _state;
private int x;

public void DoNext()
{
switch (_state)
{
case 0:
x++;
_state = 1;
break;
case 1:
x++; // This is of course the same as previous, but I'm matching
// the code in your question. There's no reason why it need
// not be something else.
_state = 2;
break;
case 2:
x++;
_state = 3;
break;
case 3:
x++;
_state = 0;
break;
}
}
}

private class Loop1 : IStateMachine
{
private int _state;
private int x;

public void DoNext()
{
switch (_state)
{
case 0:
Console.WriteLine("X=" + x);
_state = 1;
break;
case 1:
Console.WriteLine("X=" + x);
_state = 2;
break;
case 2:
Console.WriteLine("X=" + x);
_state = 3;
break;
case 3:
Console.WriteLine("X=" + x);
_state = 0;
break;
}
}
}

private static void Driver()
{
// We could have all manner of mechanisms for deciding which to call, e.g. keep calling one and
// then the other, and so on. I'm going to do a simple time-based one here:
var stateMachines = new IStateMachine[] { new Loop0(), new Loop1() };
for (int i = 0;; i = (i + 1) % stateMachines.Length)
{
var cur = stateMachines [i];
DateTime until = DateTime.UtcNow.AddMilliseconds (100);
do
{
cur.DoNext ();
} while (DateTime.UtcNow < until);
}
}

这有两个大问题:

  1. 每个中的x 是一个单独的x。我们需要将 int 装箱或将其包装在引用类型中,以便两种方法都可以访问同一个变量。
  2. 您的循环与这些状态机之间的关系不是很清楚。

幸运的是,已经存在一种方法(实际上不止一种)可以在 C# 中编写一个方法,该方法被转换为一个状态机,其中包含一个用于移动到处理这两个问题的下一个状态的方法:

private static int x;

private static IEnumerator Loop0()
{
for(;;)
{
x++;
yield return null;
x++;
yield return null;
x++;
yield return null;
x++;
yield return null;
}
}

private static IEnumerator Loop1()
{
for(;;)
{
Console.WriteLine("X=" + x);
yield return null;
Console.WriteLine("X=" + x);
yield return null;
Console.WriteLine("X=" + x);
yield return null;
Console.WriteLine("X=" + x);
yield return null;
}
}

private static void Driver()
{
// Again, I'm going to do a simple time-based mechanism here:
var stateMachines = new IEnumerator[] { Loop0(), Loop1() };
for (int i = 0;; i = (i + 1) % stateMachines.Length)
{
var cur = stateMachines [i];
DateTime until = DateTime.UtcNow.AddMilliseconds (100);
do
{
cur.MoveNext ();
} while (DateTime.UtcNow < until);
}
}

现在不仅很容易看出这与您的循环有何关系(这两个方法中的每一个都有相同的循环,只是添加了 yield return 语句),而且 的共享x 也为我们处理了,所以这个例子实际上显示它在增加,而不是一个看不见的 x 递增和一个始终为 0 的不同 x 正在显示。

我们还可以使用值 yielded 来提供有关我们的合作“线程”想要做什么的信息。例如返回true总是放弃自己的时间片(相当于在C#多线程代码中调用Thread.Yield()):

private static int x;

private static IEnumerator<bool> Loop0()
{
for(;;)
{
x++;
yield return false;
x++;
yield return false;
x++;
yield return false;
x++;
yield return true;
}
}

private static IEnumerator<bool> Loop1()
{
for(;;)
{
Console.WriteLine("X=" + x);
yield return false;
Console.WriteLine("X=" + x);
yield return false;
Console.WriteLine("X=" + x);
yield return false;
Console.WriteLine("X=" + x);
yield return true;
}
}

private static void Driver()
{
// The same simple time-based one mechanism, but this time each coroutine can
// request that the rest of its time-slot be abandoned.
var stateMachines = new IEnumerator<bool>[] { Loop0(), Loop1() };
for (int i = 0;; i = (i + 1) % stateMachines.Length)
{
var cur = stateMachines [i];
DateTime until = DateTime.UtcNow.AddMilliseconds (100);
do
{
cur.MoveNext ();
} while (!cur.Current && DateTime.UtcNow < until);
}
}

因为我在这里使用了 bool,所以我只有两个状态会影响 Driver()(我的简单调度程序)的行为。显然,更丰富的数据类型将允许更多选项,但也更复杂。

一种可能性是让你的编译器有一种必须返回 void 的方法(类似于 yieldawait 有限制)关于在 C# 中使用它们的方法的返回类型),其中可能包含关键字,例如 thread opportunitythread yieldthread leave映射到上述 C# 中的 yield return falseyield return trueyield break

当然,协作需要明确的代码来说明其他“线程”何时可能有机会运行,在本例中由 yield return 完成。对于那种我们喜欢用 C# 为它可以运行的操作系统编写的抢占式多线程,时间片可以在任何时候结束,而不仅仅是我们明确允许的地方,它需要你编译源代码来产生这样的状态机,而无需在该源中进行说明。这仍然是合作的,但在编译时会强制将合作排除在代码之外。

真正的抢占式多线程需要有某种方式来存储切换到另一个线程时每个循环的当前状态(就像 .NET 程序中每个线程的堆栈一样)。在虚拟操作系统中,您可以通过在底层操作系统线程之上构建线程来实现这一点。在非虚拟操作系统中,您可能必须构建更接近金属的线程机制,调度程序会在线程更改时更改指令指针,

关于c# - 如何在 C# 中执行 "interrupt"的 while 循环并返回到同一位置(不使用任何线程),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33900928/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com