线程未按预期启动
Threads do not start as expected
我正在尝试做一个测试,看看某人是否有某些技能。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class timerup
{
public bool timeup = false;
}
class Program
{
public static void timer()
{
for (int i = 1; i < 3; i++)
{
System.Threading.Thread.Sleep(1000);
if (i == 5)
{
object a;
a = true;
a = new timerup();
timerup ClassRef;
ClassRef = (timerup)a;
ClassRef.timeup = true;
}
}
}
static void Main(string[] args)
{
Console.Title = "The Secret Agent Test";
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Welcome, agent. This is the test to see if\nyou are good enough to be a full member of the OT Secret Agency.");
Console.WriteLine("Do you want to continue? [Y/N]");
string cont = Console.ReadLine();
if (cont == "y" || cont =="Y")
{
Console.Clear();
Console.WriteLine("Let's continue the test.");
Console.WriteLine("Crack the password:");
Console.WriteLine("Username: IDIOT_NOOB1337\nPROFILE: Likes memes such as doge.\nIs an elitist (Over the things he likes)\nOnly uses the word idiot as an insult");
Console.WriteLine("Password:");
string pass1 = Console.ReadLine();
if (pass1 == "AnyoneWhoDoesn'tLikeDogeIsAnIdiot" || pass1 == "anyonewhodoesn'tlikedogeisanidiot")
{
Console.WriteLine("Account accessed.");
Console.WriteLine("Stage 1 Complete.");
Console.WriteLine("Loading next level...");
System.Threading.Thread.Sleep(2000);
Console.WriteLine("Level 2 loaded.");
System.Threading.Thread.Sleep(1000);
Console.Clear();
Console.WriteLine("Nice. You certainly have skill. But this test.... determines speed of mind.");
System.Threading.Thread.Sleep(2500);
Console.Clear();
Console.WriteLine("You only have two seconds to answer the next question. Press any key when ready.");
Console.ReadKey();
Console.Clear();
Console.WriteLine("What is 12x12?!"); // QUESTION
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(timer)); // SUCH COMPLEX CODE FOR A TIMER... WTF.
string product = Console.ReadLine();
object b;
b = true;
b = new timerup();
timerup ClassRef;
ClassRef = (timerup)b;
bool timerthing = ClassRef.timeup;
if (product != "144" || timerthing == true)
{
Console.WriteLine("Sorry, you are incorrect. Restart the test again.");
System.Threading.Thread.Sleep(2000);
Console.Clear();
System.Environment.Exit(-1);
}
else
{
Console.WriteLine("Impressive. Your mind is fast, too. Well, be prepared for the next test. Pressure.");
}
}
}
}
}
}
线程不执行;我怀疑这是因为 string product = Console.ReadLine();
位。本次测验的第二题是 12x12,你有 2 秒的时间作答,除了计算这 2 秒的线程没有执行……为什么……?如果您知道,我该如何解决?
您只创建了一个话题。你也应该开始吧。
System.Threading.Thread t = new System.Threading.Thread(timer);
t.Start();
只是把这个写下来作为一个例子,说明如何在不使用线程的情况下检查已经过了多长时间。
bool isInTime = false;
var start = DateTime.Now;
Console.WriteLine("answer this in 5 seconds, what is 2x2");
var answer = Console.ReadLine();
if ((DateTime.Now - start).TotalSeconds <= 5)
isInTime = true;
if (isInTime && answer == "4")
Console.WriteLine("Good job you are now an agent");
else
Console.WriteLine("To slow and too dumb");
Console.ReadKey();
秒表是另一种选择:http://www.dotnetperls.com/stopwatch
如果你真的想要线程(对于这个问题来说太过分了)这里有一些很好的例子:https://msdn.microsoft.com/en-us/library/ts553s52(v=vs.110).aspx
这两个答案是当场的,所以让我补充一下如何创建一个不那么复杂的计时器:)
var timeIsUp = false;
var timer = new Timer(_ => { timeIsUp = true; }, null, 5000, Timeout.Infinite);
但总的来说,@JensB 是绝对正确的 - 使用多线程应该是 last 选项。正确处理多线程非常困难,因此避免它是一个相当不错的策略。我展示的 Timer
示例也是多线程的 - 定时器的回调将发生在不同的线程上。这引入了同步问题,但对于像这样的简单情况,它们不应该太痛苦。要改进这一点,您至少要确保本地更新安全:
var syncObject = new object();
var timeIsUp = false;
var timer = new Timer(_ => { lock (syncObject) { timeIsUp = true; } }, null, 5000,
Timeout.Infinite);
var answer = Console.ReadLine();
lock (syncObject)
{
if (timeIsUp) ...
}
最后,如今完全没有必要手动使用 Thread
。使用 Task
s 进行并发和多线程要容易得多。例如:
var timerTask = Task.Delay(5000);
var answer = Console.ReadLine();
if (timerTask.IsCompleted) Console.WriteLine("Too late");
IMO 的最佳选择是使用适当的异步 API - 遗憾的是,.NET Console
class 没有这些。虽然很傻,但这似乎是一个相当不错的选择:
void Main()
{
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(2));
var task = Task.Run(() => ReadLineFromConsole(cts.Token));
task.Wait(cts.Token);
if (task.IsCanceled)
{
Console.WriteLine("Too slow!");
return;
}
var result = task.Result;
if (result != "144")
{
Console.WriteLine("Wrong!");
return;
}
// Continue
}
public string ReadLineFromConsole(CancellationToken token)
{
var buffer = new StringBuilder();
int ch;
while (!token.IsCancellationRequested)
{
Console.In.Peek();
token.ThrowIfCancellationRequested();
ch = Console.In.Read();
if (ch == -1) return buffer.Length > 0 ? buffer.ToString() : null;
if (ch == '\r' || ch == '\n')
{
if (ch == '\r' && Console.In.Peek() == '\n') Console.In.Read();
return buffer.ToString();
}
buffer.Append((char)ch);
}
token.ThrowIfCancellationRequested();
// Shouldn't be reached, but the compiler doesn't know that.
return null;
}
这种方法的有趣之处在于,即使用户没有按回车键,我也可以退出应用程序(并中止输入)。它还允许您使用 await
将复杂的工作流程联系在一起,尽管这在控制台应用程序中有点棘手。
辅助方法 ReadLineFromConsole
实际上与通常的 ReadLine
方法工作相同,但是,它还会检查取消,并防止它从以后的 "stealing" 数据中获取 ReadLine
调用,它会先 Peek
。这不会使其成为线程安全的——您仍然不应该同时从不同的线程使用多个 readlines。但这确实意味着我们可以在输出最终到来时忽略它。请记住,线程将一直等待,直到控制台输入到来 - 不要使用它来启动多个同时请求,除非确保最终有一些输入(例如,在 [ 之间使用通常的 Console.ReadLine
=19=] 电话等)。
对您的代码进行一些重构并解决您的问题:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace ConsoleApplication2
{
class Program
{
static void WriteText(params string[] lines) { WriteText(0, lines); }
static void WriteText(double delaySecs, params string[] lines)
{
for (int i = 0; i < lines.Length; i++) Console.WriteLine(lines[i]);
if (delaySecs > 0) Thread.Sleep(TimeSpan.FromSeconds(delaySecs));
}
static void Main(string[] args)
{
Console.Title = "The Secret Agent Test";
Console.ForegroundColor = ConsoleColor.Green;
WriteText("Welcome, agent. This is the test to see if\nyou are good enough to be a full member of the OT Secret Agency.", "Do you want to continue? [Y/N]");
var readk = Console.ReadKey();
if (readk.Key == ConsoleKey.Y || readk.Key == ConsoleKey.N)
{
Console.Clear();
WriteText("Let's continue the test.\n", "Crack the password:\n", "Username: IDIOT_NOOB1337\nPROFILE: Likes memes such as doge.",
"Is an elitist (Over the things he likes)", "Only uses the word idiot as an insult", "Password:");
string pass1 = Console.ReadLine();
if (pass1 != "AnyoneWhoDoesn'tLikeDogeIsAnIdiot" && pass1 != "anyonewhodoesn'tlikedogeisanidiot") return;
WriteText(2, "Account accessed.", "Stage 1 Complete.", "Loading next level...");
WriteText(1, "Level 2 loaded.");
Console.Clear();
WriteText(2.5, "Nice. You certainly have skill. But this test.... determines speed of mind.");
Console.Clear();
Console.WriteLine("You only have two seconds to answer the next question. Press any key when ready.");
Console.ReadKey();
Console.Clear();
Console.WriteLine("What is 12x12?!"); // QUESTION
int allowedTime = 2 * 1000; // time allowed
new Thread(() =>
{
Stopwatch s = new Stopwatch();
s.Start();
while (s.ElapsedMilliseconds < allowedTime) { }
WriteText(2, "Sorry, you're too late. Restart the test again.");
Console.Clear();
Environment.Exit(-1);
}).Start();
string product = Console.ReadLine();
if (product == "144") Console.WriteLine("Impressive. Your mind is fast, too. Well, be prepared for the next test. Pressure.");
WriteText(2, "Sorry, you are incorrect. Restart the test again.");
Console.Clear();
}
}
}
}
我正在尝试做一个测试,看看某人是否有某些技能。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class timerup
{
public bool timeup = false;
}
class Program
{
public static void timer()
{
for (int i = 1; i < 3; i++)
{
System.Threading.Thread.Sleep(1000);
if (i == 5)
{
object a;
a = true;
a = new timerup();
timerup ClassRef;
ClassRef = (timerup)a;
ClassRef.timeup = true;
}
}
}
static void Main(string[] args)
{
Console.Title = "The Secret Agent Test";
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Welcome, agent. This is the test to see if\nyou are good enough to be a full member of the OT Secret Agency.");
Console.WriteLine("Do you want to continue? [Y/N]");
string cont = Console.ReadLine();
if (cont == "y" || cont =="Y")
{
Console.Clear();
Console.WriteLine("Let's continue the test.");
Console.WriteLine("Crack the password:");
Console.WriteLine("Username: IDIOT_NOOB1337\nPROFILE: Likes memes such as doge.\nIs an elitist (Over the things he likes)\nOnly uses the word idiot as an insult");
Console.WriteLine("Password:");
string pass1 = Console.ReadLine();
if (pass1 == "AnyoneWhoDoesn'tLikeDogeIsAnIdiot" || pass1 == "anyonewhodoesn'tlikedogeisanidiot")
{
Console.WriteLine("Account accessed.");
Console.WriteLine("Stage 1 Complete.");
Console.WriteLine("Loading next level...");
System.Threading.Thread.Sleep(2000);
Console.WriteLine("Level 2 loaded.");
System.Threading.Thread.Sleep(1000);
Console.Clear();
Console.WriteLine("Nice. You certainly have skill. But this test.... determines speed of mind.");
System.Threading.Thread.Sleep(2500);
Console.Clear();
Console.WriteLine("You only have two seconds to answer the next question. Press any key when ready.");
Console.ReadKey();
Console.Clear();
Console.WriteLine("What is 12x12?!"); // QUESTION
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(timer)); // SUCH COMPLEX CODE FOR A TIMER... WTF.
string product = Console.ReadLine();
object b;
b = true;
b = new timerup();
timerup ClassRef;
ClassRef = (timerup)b;
bool timerthing = ClassRef.timeup;
if (product != "144" || timerthing == true)
{
Console.WriteLine("Sorry, you are incorrect. Restart the test again.");
System.Threading.Thread.Sleep(2000);
Console.Clear();
System.Environment.Exit(-1);
}
else
{
Console.WriteLine("Impressive. Your mind is fast, too. Well, be prepared for the next test. Pressure.");
}
}
}
}
}
}
线程不执行;我怀疑这是因为 string product = Console.ReadLine();
位。本次测验的第二题是 12x12,你有 2 秒的时间作答,除了计算这 2 秒的线程没有执行……为什么……?如果您知道,我该如何解决?
您只创建了一个话题。你也应该开始吧。
System.Threading.Thread t = new System.Threading.Thread(timer);
t.Start();
只是把这个写下来作为一个例子,说明如何在不使用线程的情况下检查已经过了多长时间。
bool isInTime = false;
var start = DateTime.Now;
Console.WriteLine("answer this in 5 seconds, what is 2x2");
var answer = Console.ReadLine();
if ((DateTime.Now - start).TotalSeconds <= 5)
isInTime = true;
if (isInTime && answer == "4")
Console.WriteLine("Good job you are now an agent");
else
Console.WriteLine("To slow and too dumb");
Console.ReadKey();
秒表是另一种选择:http://www.dotnetperls.com/stopwatch
如果你真的想要线程(对于这个问题来说太过分了)这里有一些很好的例子:https://msdn.microsoft.com/en-us/library/ts553s52(v=vs.110).aspx
这两个答案是当场的,所以让我补充一下如何创建一个不那么复杂的计时器:)
var timeIsUp = false;
var timer = new Timer(_ => { timeIsUp = true; }, null, 5000, Timeout.Infinite);
但总的来说,@JensB 是绝对正确的 - 使用多线程应该是 last 选项。正确处理多线程非常困难,因此避免它是一个相当不错的策略。我展示的 Timer
示例也是多线程的 - 定时器的回调将发生在不同的线程上。这引入了同步问题,但对于像这样的简单情况,它们不应该太痛苦。要改进这一点,您至少要确保本地更新安全:
var syncObject = new object();
var timeIsUp = false;
var timer = new Timer(_ => { lock (syncObject) { timeIsUp = true; } }, null, 5000,
Timeout.Infinite);
var answer = Console.ReadLine();
lock (syncObject)
{
if (timeIsUp) ...
}
最后,如今完全没有必要手动使用 Thread
。使用 Task
s 进行并发和多线程要容易得多。例如:
var timerTask = Task.Delay(5000);
var answer = Console.ReadLine();
if (timerTask.IsCompleted) Console.WriteLine("Too late");
IMO 的最佳选择是使用适当的异步 API - 遗憾的是,.NET Console
class 没有这些。虽然很傻,但这似乎是一个相当不错的选择:
void Main()
{
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(2));
var task = Task.Run(() => ReadLineFromConsole(cts.Token));
task.Wait(cts.Token);
if (task.IsCanceled)
{
Console.WriteLine("Too slow!");
return;
}
var result = task.Result;
if (result != "144")
{
Console.WriteLine("Wrong!");
return;
}
// Continue
}
public string ReadLineFromConsole(CancellationToken token)
{
var buffer = new StringBuilder();
int ch;
while (!token.IsCancellationRequested)
{
Console.In.Peek();
token.ThrowIfCancellationRequested();
ch = Console.In.Read();
if (ch == -1) return buffer.Length > 0 ? buffer.ToString() : null;
if (ch == '\r' || ch == '\n')
{
if (ch == '\r' && Console.In.Peek() == '\n') Console.In.Read();
return buffer.ToString();
}
buffer.Append((char)ch);
}
token.ThrowIfCancellationRequested();
// Shouldn't be reached, but the compiler doesn't know that.
return null;
}
这种方法的有趣之处在于,即使用户没有按回车键,我也可以退出应用程序(并中止输入)。它还允许您使用 await
将复杂的工作流程联系在一起,尽管这在控制台应用程序中有点棘手。
辅助方法 ReadLineFromConsole
实际上与通常的 ReadLine
方法工作相同,但是,它还会检查取消,并防止它从以后的 "stealing" 数据中获取 ReadLine
调用,它会先 Peek
。这不会使其成为线程安全的——您仍然不应该同时从不同的线程使用多个 readlines。但这确实意味着我们可以在输出最终到来时忽略它。请记住,线程将一直等待,直到控制台输入到来 - 不要使用它来启动多个同时请求,除非确保最终有一些输入(例如,在 [ 之间使用通常的 Console.ReadLine
=19=] 电话等)。
对您的代码进行一些重构并解决您的问题:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace ConsoleApplication2
{
class Program
{
static void WriteText(params string[] lines) { WriteText(0, lines); }
static void WriteText(double delaySecs, params string[] lines)
{
for (int i = 0; i < lines.Length; i++) Console.WriteLine(lines[i]);
if (delaySecs > 0) Thread.Sleep(TimeSpan.FromSeconds(delaySecs));
}
static void Main(string[] args)
{
Console.Title = "The Secret Agent Test";
Console.ForegroundColor = ConsoleColor.Green;
WriteText("Welcome, agent. This is the test to see if\nyou are good enough to be a full member of the OT Secret Agency.", "Do you want to continue? [Y/N]");
var readk = Console.ReadKey();
if (readk.Key == ConsoleKey.Y || readk.Key == ConsoleKey.N)
{
Console.Clear();
WriteText("Let's continue the test.\n", "Crack the password:\n", "Username: IDIOT_NOOB1337\nPROFILE: Likes memes such as doge.",
"Is an elitist (Over the things he likes)", "Only uses the word idiot as an insult", "Password:");
string pass1 = Console.ReadLine();
if (pass1 != "AnyoneWhoDoesn'tLikeDogeIsAnIdiot" && pass1 != "anyonewhodoesn'tlikedogeisanidiot") return;
WriteText(2, "Account accessed.", "Stage 1 Complete.", "Loading next level...");
WriteText(1, "Level 2 loaded.");
Console.Clear();
WriteText(2.5, "Nice. You certainly have skill. But this test.... determines speed of mind.");
Console.Clear();
Console.WriteLine("You only have two seconds to answer the next question. Press any key when ready.");
Console.ReadKey();
Console.Clear();
Console.WriteLine("What is 12x12?!"); // QUESTION
int allowedTime = 2 * 1000; // time allowed
new Thread(() =>
{
Stopwatch s = new Stopwatch();
s.Start();
while (s.ElapsedMilliseconds < allowedTime) { }
WriteText(2, "Sorry, you're too late. Restart the test again.");
Console.Clear();
Environment.Exit(-1);
}).Start();
string product = Console.ReadLine();
if (product == "144") Console.WriteLine("Impressive. Your mind is fast, too. Well, be prepared for the next test. Pressure.");
WriteText(2, "Sorry, you are incorrect. Restart the test again.");
Console.Clear();
}
}
}
}