关于lock的三种情况?
主程序都一样,有三种情况,请问那种情况可以锁住,使B函数在FOO之后运行??为什么?static void Main(string[] args)
{
A obj = new A();
new Thread((ThreadStart)delegate { obj.Foo(); }).Start();
Thread.Sleep(10);
obj.B();
Console.ReadKey();
}
类A,有三种写法:
第一种:
public class A
{
static object i = 1;
public void Foo()
{
Console.WriteLine("before lock");
lock (i)
{
i = 2;
Console.WriteLine("enter lock and start wait");
Thread.Sleep(10000);
Console.WriteLine("enter lock and wait over");
}
Console.WriteLine("after lock");
}
public void B()
{
lock (i)
{
Console.WriteLine("B called.");
}
}
}
第二种:与第一种的区别是注释掉一行i = 2;
public class A
{
static object i = 1;
public void Foo()
{
Console.WriteLine("before lock");
lock (i)
{
//i = 2;
Console.WriteLine("enter lock and start wait");
Thread.Sleep(10000);
Console.WriteLine("enter lock and wait over");
}
Console.WriteLine("after lock");
}
public void B()
{
lock (i)
{
Console.WriteLine("B called.");
}
}
}
第三种:比第二种又多注释掉一行,lock(i),且锁对象变为this.
public class A
{
static object i = 1;
public void Foo()
{
Console.WriteLine("before lock");
lock (this)
{
//i = 2;
Console.WriteLine("enter lock and start wait");
Thread.Sleep(10000);
Console.WriteLine("enter lock and wait over");
}
Console.WriteLine("after lock");
}
public void B()
{
//lock (this)
{
Console.WriteLine("B called.");
}
}
} --------------------编程问答-------------------- 这个题目不严谨,其实多线程很难说,
第三个情况肯定锁不住,因为Foo锁了,B没锁,B根本不会受Foo的影响,在10毫秒后执行,
第二个情况肯定锁得住,Foo和B都锁定同一个对象i,标准答案应该是第二个情况,
第一种情况绝大多数情况下锁不住,主要取决于Foo在执行i=2之间是否消耗了10毫秒,这个情况概率比较低,i=2之后,i的引用就变化了,Foo和B锁定的是不同的对象,所以不能锁住,B会在Foo没有执行完就执行了,
但也有一种可能,如果Foo lock之后碰到某些事件导致线程暂停超过10毫秒,然后才执行i=2,在此之前如果B已经开始执行,那么Foo和B仍然锁定同一个对象,可以锁得住B只是概率较小, --------------------编程问答-------------------- 哪一种其实都不一定保证B在Foo之后执行。
new Thread((ThreadStart)delegate { obj.Foo(); }).Start();
Thread.Sleep(10);
obj.B();
这个代码就不能保证先执行Foo,后执行B。
另外,第三种情况中为什么要注释掉 lock(this)呢?应该取消注释。不过尽管可以lock(this),但是尽量不要这样写。通常比较好的办法是针对对象局部(private)的变量加锁,而不要写成 lock(this),更不要写成 lock(this.GetType())。 --------------------编程问答-------------------- 我主要是对第一种情况感兴趣,为什么i = 2 后,i就变为第二个对象了? --------------------编程问答-------------------- msdn上列出比较常见的lock,比如this等...都是不安全的...你查msdn一下... --------------------编程问答-------------------- 以前处理过类似的问题你 不太记得了。
好像是相同命名空间下 有个什么事件,waitone 可以阻塞当前线程
然后其他地方再引发一个事件,被阻塞的开始运行 --------------------编程问答-------------------- 一下来自msdn:
http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx
The lock keyword ensures that one thread does not enter a critical section of code while another thread is in the critical section. If another thread tries to enter a locked code, it will wait, block, until the object is released.
The section Threading (C# and Visual Basic) discusses threading.
The lock keyword calls Enter at the start of the block and Exit at the end of the block. A ThreadInterruptedException is thrown if Interrupt interrupts a thread that is waiting to enter a lock statement.
In general, avoid locking on a public type, or instances beyond your code's control. The common constructs lock (this), lock (typeof (MyType)), and lock ("myLock") violate this guideline:
lock (this) is a problem if the instance can be accessed publicly.
lock (typeof (MyType)) is a problem if MyType is publicly accessible.
lock("myLock") is a problem because any other code in the process using the same string, will share the same lock.
Best practice is to define a private object to lock on, or a private static object variable to protect data common to all instances.
You can't use the await keyword in the body of a lock statement. --------------------编程问答-------------------- i定义为object类型,是引用类型,所以2会被装箱为Integer对象后才赋给i,i=2其实执行一次装箱,相当于:
i=new Integer(2);
这就很清楚看出i已经引用了一个新的Integer类实例,
--------------------编程问答-------------------- 因为有Thread.Sleep(10);这句,所以99.9999%会是先执行Foo,后执行B,不论如何肯定是先进入Foo然后再进入B,只有一种可能就是进入Foo但没有执行到lock的时候新线程被阻塞了,直到Thread.Sleep完还没有恢复运行,这种可能性应该很小,
--------------------编程问答-------------------- “很小”的意思是说lz所谓的lock三个问题全都是无意义的、完全不用lock了吗? --------------------编程问答-------------------- 在lz的代码中,方法FOO执行时延时10秒钟,而B立刻执行完毕。lz所谓的“使B函数在FOO之后运行”是指“先执行完FOO再执行B”,而不是指“先进入FOO再进入B”。 --------------------编程问答-------------------- I SEE
OK
--------------------编程问答-------------------- LZ这3种方法都不能 “使B函数在FOO之后运行”
这种需求用TASK最合适了 不然将Sleep()放在B函数里也成 --------------------编程问答-------------------- 要保证B函数在FOO之后运行,可以使用委托异步调用 + 回调,在回调函数里 执行B --------------------编程问答-------------------- 为什么要拿个i来当做锁,又要再次给i赋值?这不是脱了裤子放易做图,快要放出来的时候又把裤子穿上么? --------------------编程问答-------------------- 正常程序不会这么写,这应该是一道题目或者面试题,
--------------------编程问答-------------------- 先不说怎么lock,既然要求顺序执行,为什么要用不同的线程呢
补充:.NET技术 , C#