关于lock的三种情况?

iccke1 2013-08-13 01:00:39
主程序都一样,有三种情况,请问那种情况可以锁住,使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.");
}
}
}
...全文
295 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
stonespace 2013-08-17
  • 打赏
  • 举报
回复
正常程序不会这么写,这应该是一道题目或者面试题,
引用 14 楼 yuwenge 的回复:
为什么要拿个i来当做锁,又要再次给i赋值?这不是脱了裤子放屁,快要放出来的时候又把裤子穿上么?
linrachel 2013-08-17
  • 打赏
  • 举报
回复
先不说怎么lock,既然要求顺序执行,为什么要用不同的线程呢
卧_槽 2013-08-14
  • 打赏
  • 举报
回复
为什么要拿个i来当做锁,又要再次给i赋值?这不是脱了裤子放屁,快要放出来的时候又把裤子穿上么?
HopeInHeart 2013-08-14
  • 打赏
  • 举报
回复
要保证B函数在FOO之后运行,可以使用委托异步调用 + 回调,在回调函数里 执行B
五更琉璃 2013-08-14
  • 打赏
  • 举报
回复
LZ这3种方法都不能 “使B函数在FOO之后运行” 这种需求用TASK最合适了 不然将Sleep()放在B函数里也成
rovoyo 2013-08-14
  • 打赏
  • 举报
回复
I SEE OK
  • 打赏
  • 举报
回复
在lz的代码中,方法FOO执行时延时10秒钟,而B立刻执行完毕。lz所谓的“使B函数在FOO之后运行”是指“先执行完FOO再执行B”,而不是指“先进入FOO再进入B”。
  • 打赏
  • 举报
回复
“很小”的意思是说lz所谓的lock三个问题全都是无意义的、完全不用lock了吗?
stonespace 2013-08-14
  • 打赏
  • 举报
回复
因为有Thread.Sleep(10);这句,所以99.9999%会是先执行Foo,后执行B,不论如何肯定是先进入Foo然后再进入B,只有一种可能就是进入Foo但没有执行到lock的时候新线程被阻塞了,直到Thread.Sleep完还没有恢复运行,这种可能性应该很小,
引用 2 楼 sp1234 的回复:
哪一种其实都不一定保证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())。
stonespace 2013-08-14
  • 打赏
  • 举报
回复
i定义为object类型,是引用类型,所以2会被装箱为Integer对象后才赋给i,i=2其实执行一次装箱,相当于: i=new Integer(2); 这就很清楚看出i已经引用了一个新的Integer类实例,
引用 3 楼 iccke1 的回复:
我主要是对第一种情况感兴趣,为什么i = 2 后,i就变为第二个对象了?
宝_爸 2013-08-13
  • 打赏
  • 举报
回复
一下来自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.
  • 打赏
  • 举报
回复
以前处理过类似的问题你 不太记得了。 好像是相同命名空间下 有个什么事件,waitone 可以阻塞当前线程 然后其他地方再引发一个事件,被阻塞的开始运行
wonkju 2013-08-13
  • 打赏
  • 举报
回复
msdn上列出比较常见的lock,比如this等...都是不安全的...你查msdn一下...
iccke1 2013-08-13
  • 打赏
  • 举报
回复
我主要是对第一种情况感兴趣,为什么i = 2 后,i就变为第二个对象了?
  • 打赏
  • 举报
回复
哪一种其实都不一定保证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())。
stonespace 2013-08-13
  • 打赏
  • 举报
回复
这个题目不严谨,其实多线程很难说, 第三个情况肯定锁不住,因为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只是概率较小,

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧