使用锁时,我是否需要锁定我的锁?从我的测试我不需要这样做,但我想确保。另外,如何格式化我发布的代码,使其具有正确的架构颜色?它要求我添加更多细节,但我真的不知道要添加什么 - 我还要问(来自比我更有经验的人)我的内容是否正确并且可以在不抛出跨线程异常的情况下工作。
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);
}
}
}
答案 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。非常原子,非常线程安全,不承载互斥锁的重量(通过锁定)。