这是我想出的用于在控制台内暂停/恢复活动线程的解决方案......
它需要第二个线程用于输入,主循环也会做出反应。但是我对C#的无知让我想知道是否有更简单的解决方案?也许可以单独使用主线程完成一个?
基本上,我正在测试几个会在定义的FPS上迭代的东西,我希望能够通过键盘输入暂停和恢复迭代。任何反馈都表示赞赏。
class TestLoops
{
int targetMainFPS = 5;
int targetInputFPS = 3;
bool CONTINUE = true;
Thread testLoop, testLoop2;
ConsoleKeyInfo cki;
ManualResetEvent resetThread = new ManualResetEvent(true); //How to correctly pause threads in C#.
public void Resume() { resetThread.Set(); }
public void Pause() { resetThread.Reset(); }
public TestLoops()
{
//_start = DateTime.Now.Ticks;
Console.Write("CreatingLoop...");
this.testLoop = new Thread(MainLoop);
this.testLoop.Start();
this.testLoop2 = new Thread(InputLoop);
this.testLoop2.Start();
}
void MainLoop()
{
long _current = 0;
long _last = 0;
Console.Write("MainLoopStarted ");
while(CONTINUE)
{
resetThread.WaitOne();
_current = DateTime.Now.Ticks / 1000;
if(_current > _last + (1000 / targetMainFPS) )
{
_last = _current;
//Do something...
Console.Write(".");
}
else
{
System.Threading.Thread.Sleep(10);
}
}
}
void InputLoop()
{
long _current = 0;
long _last = 0;
Console.Write("InputLoopStarted ");
while(CONTINUE)
{
_current = DateTime.Now.Ticks / 1000;
if(_current > _last + (1000 / targetInputFPS))
{
_last = _current;
//Manage keyboard Input
this.cki = Console.ReadKey(true);
//Console.Write(":");
if(this.cki.Key == ConsoleKey.Q)
{
//MessageBox.Show("'Q' was pressed.");
CONTINUE = false;
}
if(this.cki.Key == ConsoleKey.P)
{
this.Pause();
}
if(this.cki.Key == ConsoleKey.R)
{
this.Resume();
}
}
else
{
System.Threading.Thread.Sleep(10);
}
}
}
public static void Main(string[] args)
{
TestLoops test = new TestLoops();
}
}
答案 0 :(得分:3)
您可以使用非阻止Console.KeyAvailable
检查来大幅简化它。这样,您就可以从主线程执行所有代码:
using System;
using System.Threading;
class TestLoops
{
const int targetFPS = 5;
public static void Main(string[] args)
{
bool _continue = true;
DateTime _last = DateTime.MinValue;
while (_continue)
{
if (Console.KeyAvailable)
{
ConsoleKeyInfo cki = Console.ReadKey(true);
if (cki.Key == ConsoleKey.Q)
{
Console.WriteLine("\n'Q' was pressed.");
_continue = false;
}
if (cki.Key == ConsoleKey.P)
{
Console.WriteLine("\n'P' was pressed; press 'R' to resume.");
// Block until 'R' is pressed.
while (Console.ReadKey(true).Key != ConsoleKey.R)
; // Do nothing.
Console.WriteLine("'R' was pressed.");
}
}
DateTime _current = DateTime.Now;
if (_current - _last > TimeSpan.FromMilliseconds(1000F / targetFPS))
{
_last = _current;
// Do something...
Console.Write(".");
}
else
{
System.Threading.Thread.Sleep(10);
}
}
}
}
修改:回复评论。
小心点。由于Console.ReadKey
调用,下面的代码会阻止,而不是while
循环。 while
循环只有这样,如果用户输入R
以外的字符,程序将丢弃它并等待输入另一个字符。
// Block until 'R' is pressed.
while (Console.ReadKey(true).Key != ConsoleKey.R)
; // Do nothing.
如果您想要阻止按下任何字符,您只需使用:
Console.ReadKey(true);
答案 1 :(得分:0)
这样可行,是的。您可以考虑的唯一事情就是确保工作线程在您按下Q
键时,即使先前已暂停,也会停止:
if(this.cki.Key == ConsoleKey.Q)
{
CONTINUE = false;
this.Resume(); // <-- make sure that the worker thread resumes
}
作为旁注,常量FPS通常由跳过帧维护,而不是暂停线程。暂停线程是不精确的,并且不允许微调动画速度。 Thread.Sleep
在不同硬件上的行为也可能不同,并且分辨率可能相当差(最小OS时间片约为16ms IIRC)。