Reputation: 5338
Below is a C# code example which is a verbatim translation of a broken Java code (which has proven to break (i. e. the 2nd thread may fail to observe the change of sharedValue
value) at least on Mac OS X 10.9, Java 1.8 (64 bit), Arrandale (1 socket x 2 core x 2 HT = 4 HW threads)):
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 + "%");
}
}
Amazingly, no matter many times I run the above C# code on .NET 4.0/Windows XP (32 bit), I haven't observed a single failure. Nor is there any failure when running on Mono (64 bit), Mac OS X. In both cases, I only see a single CPU core busy.
Can you suggest a C# code example which makes an incorrect use of a shared variable and fails unless the variable is marked volatile
?
Upvotes: 2
Views: 317
Reputation: 8904
This should get stuck in an infinite loop (I can't test it right now)
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");
}
}
Upvotes: 2
Reputation: 109792
Try running the RELEASE build of the following program (do NOT run it from the debugger otherwise the demonstration won't work - so run the release build via "Debug | Start without debugging"):
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();
}
}
}
The program will terminate after a second.
Now remove the volatile
from the line
private volatile bool flag = true; // <--- Remove volatile from this
After doing so, the program will now never terminate. (Tested on Windows 8 x64, .Net 4.5)
Please note, however, that in some cases it is more appropriate to use Thread.MemoryBarrier()
rather than declaring the variable volatile
, i.e.:
while (flag)
{
Thread.MemoryBarrier();
++x;
}
For more information, see http://blogs.msdn.com/b/brada/archive/2004/05/12/130935.aspx
Upvotes: 3