属性get / set中的线程锁定对象

时间:2014-04-29 18:26:23

标签: c# multithreading locking

使用锁时,我是否需要锁定我的锁?从我的测试我不需要这样做,但我想确保。另外,如何格式化我发布的代码,使其具有正确的架构颜色?它要求我添加更多细节,但我真的不知道要添加什么 - 我还要问(来自比我更有经验的人)我的内容是否正确并且可以在不抛出跨线程异常的情况下工作。

class exam
{
    private static readonly exam x = new exam();
    private static readonly object lckobj = new object();

    private int i;
    private int _count;

    private exam() { }

    public static exam AccessPoint
    {
        get
        {
            return x;
        }
    }

    public int myInt
    {
        get
        {
            return i;
        }
        set
        {
            lock(lckobj)
            {
                i = value;
            }
        }
    }

    public int Count
    {
        get
        {
            return _count;
        }
        set
        {
            lock(lckobj)
            {
                _count = value;
            }
        }
    }

}

class myDemo
{
    Random r = new Random();
    bool b = false;
    Thread[] t = new Thread[3];

    public myDemo()
    {
        for(int i=0; i < 3; i++)
        {
            t[i] = new Thread(new ThreadStart(thread1));
            t[i].Start();
        }

        Thread checks = new Thread(new ThreadStart(checkB));
        checks.Start();

    }

    void checkB()
    {
        var x = exam.AccessPoint;
        while (!b)
        {
            b = (x.Count >= 10) ? true : false;
            Console.WriteLine("\tb:{0}\tCount:{1}", b, x.Count);
            Thread.Sleep(100);
        }
    }

    void thread1()
    {
        var x = exam.AccessPoint;

        while (!b)
        {
            Thread.Sleep(r.Next(500, 1000));

            x.myInt = r.Next(1, 10);
            x.Count = x.Count + 1;
            Console.WriteLine(x.myInt);
        }
    }
}

3 个答案:

答案 0 :(得分:1)

即使如果你在get代码上添加锁定仍然也无法正常工作,尽管可能会有更多可能的事情发生如果你不这样做,那就错了。

以下一行存在问题,无法通过锁定Count来修复:

x.Count = x.Count + 1;

这里即使你添加了锁,一个线程完全可以读取一个值,在更新之前停止,然后让另一个线程读取该值,增加计数,然后再写回来。当第一个线程继续时,将覆盖该写入。 Count中没有任何锁定会改变这一点。

当然,如果lock中没有Count,则不会引入内存障碍,因此允许对该值的读取读取陈旧值,这可能会进一步加剧先前的问题。

答案 1 :(得分:1)

同时通过多个线程读取变量的值是安全的 在同一时间由多个线程向变量写入值不安全 在一个或多个线程正在读取此变量的同时,通过一个线程将值写入变量不安全

因此需要在setter和getter中使用相同的锁定 @Servy答案中描述的问题需要更好的解决方案。任何包含所谓的“SELECT FOR UPDATE”的锁定机制(我知道这适用于DB,但问题是相同的)应该足够好了。

您甚至应该重复使用代码中已有的锁。将它设为public,因为它是readonly,并且在这种情况下从外部使用它:

lock(exam.lckobj){
    exam.myInt = exam.myInt + 1;
}

答案 2 :(得分:0)

对于整数值,请使用Interlocked.Read和Interlock.Exchange。非常原子,非常线程安全,不承载互斥锁的重量(通过锁定)。