不眠等待?
Waiting without Sleeping?
我想做的是启动一个函数,然后将 bool 更改为 false,稍等片刻,然后再次将其变为 true。但是我想在函数不必等待的情况下执行此操作,我该怎么做?
我只能使用 Visual C# 2010 Express。
这是有问题的代码。我正在尝试接收用户输入(例如向右箭头)并相应地移动,但在角色移动时不允许进一步输入。
x = Test.Location.X;
y = Test.Location.Y;
if (direction == "right")
{
for (int i = 0; i < 32; i++)
{
x++;
Test.Location = new Point(x, y);
Thread.Sleep(31);
}
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
int xmax = Screen.PrimaryScreen.Bounds.Width - 32;
int ymax = Screen.PrimaryScreen.Bounds.Height - 32;
if (e.KeyCode == Keys.Right && x < xmax) direction = "right";
else if (e.KeyCode == Keys.Left && x > 0) direction = "left";
else if (e.KeyCode == Keys.Up && y > 0) direction = "up";
else if (e.KeyCode == Keys.Down && y < ymax) direction = "down";
if (moveAllowed)
{
moveAllowed = false;
Movement();
}
moveAllowed = true;
}
使用Task.Delay:
Task.Delay(1000).ContinueWith((t) => Console.WriteLine("I'm done"));
或
await Task.Delay(1000);
Console.WriteLine("I'm done");
对于较旧的框架,您可以使用以下内容:
var timer = new System.Timers.Timer(1000);
timer.Elapsed += delegate { Console.WriteLine("I'm done"); };
timer.AutoReset = false;
timer.Start();
根据问题中的描述举例:
class SimpleClass
{
public bool Flag { get; set; }
public void function()
{
Flag = false;
var timer = new System.Timers.Timer(1000);
timer.Elapsed += (src, args) => { Flag = true; Console.WriteLine("I'm done"); };
timer.AutoReset = false;
timer.Start();
}
}
我意识到答案已经被接受,我喜欢 ixSci
的答案,他建议使用 Timer
对象来实现 OP 的目标。
但是,使用 System.Timers.Timer
特别引入了线程注意事项。为了确保这种情况下的正确性,需要更多代码来正确同步布尔标志值。基本上,在读取或写入标志的任何地方,代码区域都需要在其周围定义一个锁定语句。
它必须看起来像这样:
private final object flagLock = new object();
private bool moveAllowed = true;
private System.Timers.Timer timer = new System.Timers.Timer();
public Form1()
{
this.timer.Interval = 1000;
this.timer.AutoReset = false;
this.timer.Elapsed += (s, e) =>
{
// this DOES NOT run on the UI thread, so locking IS necessary to ensure correct behavior.
this.timer.Stop();
lock (this.flagLock) {
this.moveAllowed = true;
}
};
}
// The code in this event handler runs on the UI thread.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
// Locking is necessary here too.
lock (this.flagLock) {
if (this.moveAllowed)
{
this.moveAllowed = false;
Movement();
this.timer.Start(); // wait 1 second to reset this.moveAllowed to true.
}
}
}
或者,为了避免考虑线程,也许 OP 可以考虑使用不同风格的 Timer
class。即:System.Windows.Forms.Timer
。这样,布尔标志在 UI 线程上将始终为 read/written,并且不需要任何类型的额外锁定来确保正确性。
在这种情况下,代码将如下所示:
private bool moveAllowed = true;
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
public Form1()
{
this.timer.Interval = 1000;
this.timer.Tick += (s, e) =>
{
// this runs on the UI thread, so no locking necessary.
this.timer.Stop(); // this call is necessary, because unlike System.Timers.Timer, there is no AutoReset property to do it automatically.
this.moveAllowed = true;
};
}
// The code in this event handler runs on the UI thread.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (this.moveAllowed)
{
this.moveAllowed = false;
Movement();
this.timer.Start(); // wait 1 second to reset this.moveAllowed to true.
}
}
我想做的是启动一个函数,然后将 bool 更改为 false,稍等片刻,然后再次将其变为 true。但是我想在函数不必等待的情况下执行此操作,我该怎么做?
我只能使用 Visual C# 2010 Express。
这是有问题的代码。我正在尝试接收用户输入(例如向右箭头)并相应地移动,但在角色移动时不允许进一步输入。
x = Test.Location.X;
y = Test.Location.Y;
if (direction == "right")
{
for (int i = 0; i < 32; i++)
{
x++;
Test.Location = new Point(x, y);
Thread.Sleep(31);
}
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
int xmax = Screen.PrimaryScreen.Bounds.Width - 32;
int ymax = Screen.PrimaryScreen.Bounds.Height - 32;
if (e.KeyCode == Keys.Right && x < xmax) direction = "right";
else if (e.KeyCode == Keys.Left && x > 0) direction = "left";
else if (e.KeyCode == Keys.Up && y > 0) direction = "up";
else if (e.KeyCode == Keys.Down && y < ymax) direction = "down";
if (moveAllowed)
{
moveAllowed = false;
Movement();
}
moveAllowed = true;
}
使用Task.Delay:
Task.Delay(1000).ContinueWith((t) => Console.WriteLine("I'm done"));
或
await Task.Delay(1000);
Console.WriteLine("I'm done");
对于较旧的框架,您可以使用以下内容:
var timer = new System.Timers.Timer(1000);
timer.Elapsed += delegate { Console.WriteLine("I'm done"); };
timer.AutoReset = false;
timer.Start();
根据问题中的描述举例:
class SimpleClass
{
public bool Flag { get; set; }
public void function()
{
Flag = false;
var timer = new System.Timers.Timer(1000);
timer.Elapsed += (src, args) => { Flag = true; Console.WriteLine("I'm done"); };
timer.AutoReset = false;
timer.Start();
}
}
我意识到答案已经被接受,我喜欢 ixSci
的答案,他建议使用 Timer
对象来实现 OP 的目标。
但是,使用 System.Timers.Timer
特别引入了线程注意事项。为了确保这种情况下的正确性,需要更多代码来正确同步布尔标志值。基本上,在读取或写入标志的任何地方,代码区域都需要在其周围定义一个锁定语句。
它必须看起来像这样:
private final object flagLock = new object();
private bool moveAllowed = true;
private System.Timers.Timer timer = new System.Timers.Timer();
public Form1()
{
this.timer.Interval = 1000;
this.timer.AutoReset = false;
this.timer.Elapsed += (s, e) =>
{
// this DOES NOT run on the UI thread, so locking IS necessary to ensure correct behavior.
this.timer.Stop();
lock (this.flagLock) {
this.moveAllowed = true;
}
};
}
// The code in this event handler runs on the UI thread.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
// Locking is necessary here too.
lock (this.flagLock) {
if (this.moveAllowed)
{
this.moveAllowed = false;
Movement();
this.timer.Start(); // wait 1 second to reset this.moveAllowed to true.
}
}
}
或者,为了避免考虑线程,也许 OP 可以考虑使用不同风格的 Timer
class。即:System.Windows.Forms.Timer
。这样,布尔标志在 UI 线程上将始终为 read/written,并且不需要任何类型的额外锁定来确保正确性。
在这种情况下,代码将如下所示:
private bool moveAllowed = true;
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
public Form1()
{
this.timer.Interval = 1000;
this.timer.Tick += (s, e) =>
{
// this runs on the UI thread, so no locking necessary.
this.timer.Stop(); // this call is necessary, because unlike System.Timers.Timer, there is no AutoReset property to do it automatically.
this.moveAllowed = true;
};
}
// The code in this event handler runs on the UI thread.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (this.moveAllowed)
{
this.moveAllowed = false;
Movement();
this.timer.Start(); // wait 1 second to reset this.moveAllowed to true.
}
}