下面是一个C#代码示例,它是破坏的Java代码的逐字翻译(至少在Mac OS X上已被证明会破坏(即第二个线程可能无法观察到sharedValue
值的更改) 10.9,Java 1.8(64位),Arrandale(1插槽x 2核x 2 HT = 4个HW线程)):
using System;
using System.Threading;
class ThreadTest {
/* volatile */ private int sharedValue;
private void RunAsync() {
while (this.sharedValue == 0);
}
private bool Test() {
Thread t = new Thread(this.RunAsync);
t.IsBackground = true;
t.Start();
Thread.Sleep(10);
// Yes I'm aware the operation is not atomic
this.sharedValue++;
t.Join(10);
bool success = !t.IsAlive;
if (!success) {
Console.Write('.');
}
return success;
}
static void Main() {
long failureCount = 0L;
const long testCount = 10000L;
for (long i = 0; i < testCount; i++) {
if (!new ThreadTest().Test()) {
failureCount++;
}
}
Console.WriteLine();
Console.WriteLine("Failure rate: " + 100.0 * failureCount / testCount + "%");
}
}
令人惊讶的是,无论我多次在.NET 4.0 / Windows XP(32位)上运行上述C#代码,我都没有观察到一次失败。在Mono(64位),Mac OS X上运行时也没有任何故障。在这两种情况下,我只看到一个CPU核心忙。
你能否建议一个C#代码示例,它会错误地使用共享变量并失败,除非变量标记为volatile
?
答案 0 :(得分:3)
尝试运行以下程序的RELEASE构建(不要从调试器运行它,否则演示不会起作用 - 所以通过&#34; Debug | Start而不调试&#34;)运行发布构建:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
internal class Program
{
private void run()
{
Task.Factory.StartNew(resetFlagAfter1s);
int x = 0;
while (flag)
++x;
Console.WriteLine("Done");
}
private void resetFlagAfter1s()
{
Thread.Sleep(1000);
flag = false;
}
private volatile bool flag = true;
private static void Main()
{
new Program().run();
}
}
}
程序将在一秒后终止。
现在从行
中删除volatile
private volatile bool flag = true; // <--- Remove volatile from this
这样做之后,程序将永远不会终止。 (在Windows 8 x64,.Net 4.5上测试)
但请注意,在某些情况下,使用Thread.MemoryBarrier()
而不是声明变量volatile
更合适,即:
while (flag)
{
Thread.MemoryBarrier();
++x;
}
有关详细信息,请参阅http://blogs.msdn.com/b/brada/archive/2004/05/12/130935.aspx
答案 1 :(得分:2)
这应该陷入无限循环(我现在无法测试)
public class Test
{
private bool loop = true;
public static void Main()
{
Test test = new Test();
Thread thread = new Thread(DoStuff);
thread.Start(test);
Thread.Sleep(1000);
test.loop = false;
Console.WriteLine("loop is now false");
}
private static void DoStuff(object o) {
Test test = (Test)o;
Console.WriteLine("Entering loop");
while (test.loop) {
}
Console.WriteLine("Exited loop");
}
}