【发布时间】:2019-02-07 10:39:24
【问题描述】:
Edit@Dublicate:我知道不推荐不安全地使用 Thread。我的问题是关于为什么,而不是关于随机是否是线程安全的。感谢答案,帮助我更好地理解它!
我编写了一个“噱头”程序,它应该使用 Math.Random() 和多线程在控制台窗口中显示具有随机颜色(For- 和 Background)的随机字符。为了获得更多随机性,我没有使程序“线程安全”。 (附加信息:我最初希望程序在中心显示一个 Space-Invader,我通过 Thread-Safety 实现了这一点,而且我知道,多线程应该是线程安全的,但这不是这个问题的内容)
输出如下:
程序的功能是这样的:我有一个数组,其中存储了所有带有颜色和字符的位置(X/Y)。我有一些函数可以改变这个数组,我有一些函数来显示数组。我还有一个返回随机字符的函数和一个返回随机颜色的函数。
现在我不明白的一点:有时一切都按描述工作,但有时程序开始只显示 !-Chars(感叹号)但保持随机颜色和位置:
还有一次程序只显示黑色和白色,但字符一直是随机的:
有时会发生,程序只显示 !-Chars 并且只显示黑白:
我能说的是:
我的“获取随机字符”函数如下所示:
public static char GetChar()
{
return (char)randomChar.Next(33, 150);
}
!-Char 是 Ascii-Char 33。这意味着如果程序卡住,Random-Char-Function 仅返回最低的 Random-Char (== 33 == !)
我得到了类似的颜色。我给函数一个 0 到 16 之间的随机数来取回控制台颜色:
private ConsoleColor SetColor(char ColorIndex)
{
switch (ColorIndex)
{
case (char)1:
return ConsoleColor.Black;
case (char)2:
return ConsoleColor.Blue;
case (char)3:
return ConsoleColor.Cyan;
case (char)4:
return ConsoleColor.DarkBlue;
case (char)5:
return ConsoleColor.DarkCyan;
case (char)6:
return ConsoleColor.DarkGray;
case (char)7:
return ConsoleColor.DarkGreen;
case (char)8:
return ConsoleColor.DarkMagenta;
case (char)9:
return ConsoleColor.DarkRed;
case (char)10:
return ConsoleColor.DarkYellow;
case (char)11:
return ConsoleColor.Gray;
case (char)12:
return ConsoleColor.Green;
case (char)13:
return ConsoleColor.Magenta;
case (char)14:
return ConsoleColor.Red;
case (char)15:
return ConsoleColor.White;
case (char)16:
return ConsoleColor.Yellow;
default:
return ConsoleColor.Black;
}
}
//The call looks like that:
_Data[x, y, 1] = (char)random.Next(0, 16);
我知道 random.Next(0, 16) 将返回 15 作为最大数字,而 15 是示例中的白色。如果我将 15 更改为红色,当程序卡住时,程序将显示红色而不是白色:
这意味着:当程序卡住时,Random-Char-Function 总是返回可能的最小数字 (33),而 Random-Color-Function 总是返回可能的最大数字 (15)。
问题:为什么会出现这种行为?为什么只是有时而不是每次?为什么每次都是在不同的跑步时间之后?为什么一个随机函数总是返回最大数而另一个总是返回最小数?
我的猜测是,他是因为 CPU 预测,但正如我所说,这只是一个猜测,我想知道这是如何工作的,以及为什么它采用不同的方法(最小/最大)。
这是我的一些代码,如果需要我可以发布更多代码:
//Program-Start after initialising some stuff:
public AnotherOne()
{
new Thread(DrawData).Start();
new Thread(DrawDataLR).Start();
new Thread(DrawDataRL).Start();
new Thread(DrawDataTD).Start();
new Thread(DrawDataDT).Start();
new Thread(ChangeData).Start();
ChangeData();
}
//Draw Data example for Left-Right:
private void DrawDataLR()
{
while (!_done)
{
DrawDataLeftRight();
Thread.Sleep(2);
}
}
private void DrawDataLeftRight()
{
for (int x = 0; x < _Width - 1; x++)
{
for (int y = 0; y < _Height - 1; y++)
{
Console.SetCursorPosition(x, y);
Console.BackgroundColor = SetColor(_Data[x, y, 1]);
Console.ForegroundColor = SetColor(_Data[x, y, 2]);
Console.WriteLine(_Data[x, y, 0]);
}
}
}
//Draw Data Function:
private void DrawData()
{
Random next = new Random();
int x = 1;
while (!_done)
{
x = next.Next(1, 5);
switch (x)
{
case 1:
DrawDataLeftRight();
break;
case 2:
DrawDataTopDown();
break;
case 3:
DrawDataRightLeft();
break;
case 4:
DrawDataDownTop();
break;
}
}
}
//Change Data Function with "stripes" as Example:
private void ChangeData()
{
int x = 100;
while (!_done)
{
FillRandomFeld();
Thread.Sleep(x);
ClearChar();
Thread.Sleep(x);
SetColor();
Thread.Sleep(x);
Stripes();
Thread.Sleep(x);
SetChar();
Thread.Sleep(x);
OtherStripes();
Thread.Sleep(x);
x = randomX.Next(0, 100);
}
}
private void Stripes()
{
char colr = (char)random.Next(0, 16);
for (int x = 0; x < _Width - 1; x += 4)
{
for (int y = 0; y < _Height - 1; y++)
{
if (_Data[x, y, 3] != (char)1)
{
_Data[x, y, 1] = colr;
_Data[x, y, 2] = colr;
}
}
}
}
【问题讨论】:
-
随机不是线程安全的。如果两个线程同时访问它,它的内部状态最终可能会损坏,可能会导致它总是返回相同的数字或相同的数字序列。以多线程方式访问非线程安全对象不会给您带来更多“随机性”,它会给您带来异常、崩溃以及奇怪和不可预测的行为。不要这样做。
-
查看标记的重复答案,这可能是因为您在每个线程上同时创建
Random的新实例,有效地使用相同的种子。 -
不清楚
randomX的范围是什么,因为你没有显示它;但如果它在线程之间共享:坦率地说,我只是锁定它,所以:lock (randomX) { x = randomX.Next(0, 100); };同样random -
@MarcGravell 在 ChangeData() 中使用,代码在底部。谢谢大家的重播,我会检查的。如前所述,我得到了一个线程安全的解决方案,我只是想知道为什么它是如此随机而不仅仅是崩溃。
标签: c# multithreading random console prediction