A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 宋佳强 中级黑马   /  2014-7-10 23:58  /  1592 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 宋佳强 于 2014-7-12 02:04 编辑

奇怪,为什么 C# 不允许lock一个struct ? 例如:

public void ProcessTask(int taskid){
    lock(taskid){  .....   }
}

编译说lock只能使用引用类型。有些人聪明(我想我以前也有这样的"聪明"。。),这样做: lock((object)taskid){...}

但是,实际的经验告诉我,这样行不通,lock需要的是引用,严格来说是需要对象的实例。

即使对象在意义上是相同的,但是如果不是ReferenceEquals的话,那么将作为两个实例来对待,那么C# lock 的就不是同一个东西。也就是说,当你以为这个 lock 生效的话,它其实在做无用工。

在上面的例子,由于lock((object)taskid)每执行一次,taskid都进行一次装箱,而装箱后的对象不是同一个实例(都是完完全全的新的实例),所以 lock((object)taskid){...} 是白做了。

当然,lock((object)123){} 这样的做法也是一样有问题的。

但是这种就好点:lock(“helloworld“){} 。为什么只是“好点”,而不是“没有问题”了呢。原因在于DotNet分配字符串的机制。DotNet为每个Assembly里的字符串都分配固定的空间。所以每次引用“helloworld“的时候,是同一个实例。但是这个字符串不会在其他Assembly中得到共用。如果几个Assembly都是这样写的,那么它们各自有她们自己的“helloworld“

比较好的做法:

lock(this)...
lock(typeof(ThisType))
lock(GetType())//除非你明白这是干什么,否则不要乱来。
lock(SomeType.StaticSyncObject)
lock(someinst.SyncObject)
其他的一些不好的做法

lock(“task:“+id)
lock(filename)
当然,具体lock什么东西,是设计上的协议和规范。不过要注意的是,使用lock必须明确对象是不是想象中的同一实例。

如果需要针对一个变化的值,从它的意义上的Equals方面进行 lock ,那怎么办?
这个可以参考  http://www.lostinet.com/files/ 下的 HashCodeLock (里面很多细节可以优化)

评分

参与人数 1技术分 +1 收起 理由
czwanglei + 1 赞一个!

查看全部评分

3 个回复

正序浏览
路过学习,不过很难,我还没学到!
回复 使用道具 举报
这个看起来很蛋疼,看了半天不知道想表达什么!
回复 使用道具 举报
你好,你发这种帖子的时候,请把帖子编辑为资源分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马