マルチスレッド環境でlongを共有するときの注意 (C#編)

id:nowokayがおもしろいことしてたので、.NETで試してみることにしました。

以下コード

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace VolatileSample
{
    public class VolatileSample
    {
        static long lock_ = 0;
        public static void Main(string[] args)
        {
            new Thread(delegate()
            {
                for (; ; )
                {
                    long t;

                    t = lock_;
                    long high = t >> 32;
                    long low = t & 0xffffffffL;
                    if (high != low)
                    {
                        Console.WriteLine("おわた");
                        Process.GetCurrentProcess().Kill();
                    }
                }
            }).Start();

            Random r = new Random();
            for (; ; )
            {
                long a = r.Next();
                if (a < 0) a -= Int32.MinValue;
                long t = (a << 32) + a;
                lock_ = t;
            }
        }
    }
}

案の定、.NETでもすぐ終了します。
で、Javaだとvolatile指定すればOKなんだけど、C#の場合は、longにはvolatile指定ができないようなので、lockするようにしてみます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace VolatileSample
{
    public class VolatileSample
    {
        static long lock_ = 0;
        static object lockObj = new object();
        public static void Main(string[] args)
        {
            new Thread(delegate()
            {
                for (; ; )
                {
                    long t;

                    lock (lockObj)
                    {
                        t = lock_;
                    }
                    long high = t >> 32;
                    long low = t & 0xffffffffL;
                    if (high != low)
                    {
                        Console.WriteLine("終了");
                        Process.GetCurrentProcess().Kill();
                    }
                }
            }).Start();

            Random r = new Random();
            for (; ; )
            {
                long a = r.Next();
                if (a < 0) a -= Int32.MinValue;
                long t = (a << 32) + a;

                lock (lockObj)
                {
                    lock_ = t;
                }
            }
        }
    }
}

これで終了しなくなりました。