c#线程问题
c# Thread issue
using System;
using System.Threading;
using System.Text;
class ThreadTest
{
static StringBuilder sb = new StringBuilder();
static void Main()
{
Thread t = new Thread(WriteY);
t.Start();
for(int i = 0; i < 1000; i++)
{
sb.Append("x");
}
Console.WriteLine(sb.ToString());
}
private static void WriteY()
{
for (int i = 0; i < 1000; i++)
{
sb.Append("y");
}
}
}
输出:
{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy y}
问题:
- 为什么
'x'
出现在'y'
之前?
StringBuilder
是否只接受一个线程?
- 为什么不出现这样
"xyxyxyxyx xyxyxyxy"
?
这是您要找的吗?
class Program
{
static StringBuilder sb = new StringBuilder();
static void Main()
{
Thread t = new Thread(WriteY);
t.Start();
for (int i = 0; i < 1000; i++)
{
//Console.Write("x");
sb.Append("x");
Thread.Sleep(10);
}
//t.Join();
Console.WriteLine(sb.ToString());
}
private static void WriteY()
{
for (int i = 0; i < 1000; i++)
{
//Console.Write("y");
sb.Append("y");
Thread.Sleep(10);
}
}
}
为什么'x'出现在'y'之前?
Because the main thread is not blocked at any point and continuing its execution before the resources are granted to other thread that is printing y
StringBuilder 是否只接受一个线程?
No that is not the case. Run example below.
为什么不出现这样"xyxyxyxyx xyxyxyxy"?
there is not much work so, to get that random result you need to increase the duration which is demonstrated by using sleep.
更新: 在上面的示例中,如果将循环增加到 100000 或更大,您可以看到随机性。并且您还需要添加 t.Join()
否则您的线程可能无法完成工作。
问题1和3都与Windows调度器的时间分片有关。根据 Windows 2000 Performance Guide,x86 处理器上的时间片约为 30 毫秒。自 Windows 2000 年以来,这种情况可能已经发生变化,但应该仍处于这个数量级。因此,t.Start()
仅将新线程添加到调度程序,但不会立即触发上下文切换。主线程还有其时间片的剩余部分,这显然足以打印 'x' 1,000 次。
另外,当新线程真正被调度时,它有一个完整的时间片可以打印出来'y'。由于时间充足,您不会得到模式 "xyxyxy",而是 'x's 直到主线程的时间片用完,然后 'y's 直到结束新线程的时间片,然后再次 'x's。 (至少如果有足够的 'x's 和 'y's 可以打印,根据 Simon 的评论,10,000 个 'x's 和 'y's 就是这种情况。)
问题 2 由 MSDN page on the StringBuilder 回答。在主题 "Thread Safety" 下写道 "Any public static ( Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe." 由于 Append 方法是一个实例方法,如果没有进一步的同步,您无法从不同的线程并行可靠地调用它。
using System;
using System.Threading;
using System.Text;
class ThreadTest
{
static StringBuilder sb = new StringBuilder();
static void Main()
{
Thread t = new Thread(WriteY);
t.Start();
for(int i = 0; i < 1000; i++)
{
sb.Append("x");
}
Console.WriteLine(sb.ToString());
}
private static void WriteY()
{
for (int i = 0; i < 1000; i++)
{
sb.Append("y");
}
}
}
输出: {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy y}
问题:
- 为什么
'x'
出现在'y'
之前? StringBuilder
是否只接受一个线程?- 为什么不出现这样
"xyxyxyxyx xyxyxyxy"
?
这是您要找的吗?
class Program
{
static StringBuilder sb = new StringBuilder();
static void Main()
{
Thread t = new Thread(WriteY);
t.Start();
for (int i = 0; i < 1000; i++)
{
//Console.Write("x");
sb.Append("x");
Thread.Sleep(10);
}
//t.Join();
Console.WriteLine(sb.ToString());
}
private static void WriteY()
{
for (int i = 0; i < 1000; i++)
{
//Console.Write("y");
sb.Append("y");
Thread.Sleep(10);
}
}
}
为什么'x'出现在'y'之前?
Because the main thread is not blocked at any point and continuing its execution before the resources are granted to other thread that is printing
y
StringBuilder 是否只接受一个线程?
No that is not the case. Run example below.
为什么不出现这样"xyxyxyxyx xyxyxyxy"?
there is not much work so, to get that random result you need to increase the duration which is demonstrated by using sleep.
更新: 在上面的示例中,如果将循环增加到 100000 或更大,您可以看到随机性。并且您还需要添加 t.Join()
否则您的线程可能无法完成工作。
问题1和3都与Windows调度器的时间分片有关。根据 Windows 2000 Performance Guide,x86 处理器上的时间片约为 30 毫秒。自 Windows 2000 年以来,这种情况可能已经发生变化,但应该仍处于这个数量级。因此,t.Start()
仅将新线程添加到调度程序,但不会立即触发上下文切换。主线程还有其时间片的剩余部分,这显然足以打印 'x' 1,000 次。
另外,当新线程真正被调度时,它有一个完整的时间片可以打印出来'y'。由于时间充足,您不会得到模式 "xyxyxy",而是 'x's 直到主线程的时间片用完,然后 'y's 直到结束新线程的时间片,然后再次 'x's。 (至少如果有足够的 'x's 和 'y's 可以打印,根据 Simon 的评论,10,000 个 'x's 和 'y's 就是这种情况。)
问题 2 由 MSDN page on the StringBuilder 回答。在主题 "Thread Safety" 下写道 "Any public static ( Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe." 由于 Append 方法是一个实例方法,如果没有进一步的同步,您无法从不同的线程并行可靠地调用它。