I have read some posts about volatile keyword and behaviour without this keyword.
I've especially tested the code from the answer to Illustrating usage of the volatile keyword in C#. When running, I observe the excepted behaviour in Release mode, without debugger attached. Up to that point, there is no problem.
So, as far as I understand, the following code should never exit.
public class Program
{
    private bool stopThread;
    public void Test()
    {
        while (!stopThread) { }  // Read stopThread which is not marked as volatile
        Console.WriteLine("Stopped.");
    }
    private static void Main()
    {
        Program program = new Program();
        Thread thread = new Thread(program.Test);
        thread.Start();
        Console.WriteLine("Press a key to stop the thread.");
        Console.ReadKey();
        Console.WriteLine("Waiting for thread.");
        program.stopThread = true;
        thread.Join();  // Waits for the thread to stop.
    }
}
Why does it exit? Even in Release mode, without debugger?
Update
An adaptation of the code from Illustrating usage of the volatile keyword in C#.
private bool exit;
public void Test()
{
    Thread.Sleep(500);
    exit = true;
    Console.WriteLine("Exit requested.");
}
private static void Main()
{
    Program program = new Program();
    // Starts the thread
    Thread thread = new Thread(program.Test);
    thread.Start();
    Console.WriteLine("Waiting for thread.");
    while (!program.exit) { }
}
This program does not exit after in Release mode, without debugger attached.