旧事重提了,或许很多人会奇怪,为什么 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 (里面很多细节可以优化)

C# 中的 lock的陷阱的更多相关文章

  1. 浅析C/C++中的switch/case陷阱

    浅析C/C++中的switch/case陷阱 先看下面一段代码: 文件main.cpp #include<iostream> using namespace std; int main(i ...

  2. 软件测试中LoadRunner函数中的几个陷阱

    软件测试 中 LoadRunner 函数中的几个陷阱 1.atof 在 loadrunner 中如果直接用 float f; f=atof("123.00"); lr _outpu ...

  3. C#中各种Lock的速度比较

    简单写了个小程序,比较了一下C#中各种Lock的速度(前提是都没有进入wait状态). 各进入离开Lock 1kw次,结果如下: Lock Time (ms) No lock 58 CriticalS ...

  4. 关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析

    关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析 如下代码,当我们在使用 ReentrantLock 进行加锁和解锁时,底层到底是如何帮助我们进行控制的啦 ...

  5. 一文带你看懂Java中的Lock锁底层AQS到底是如何实现的

    前言 相信大家对Java中的Lock锁应该不会陌生,比如ReentrantLock,锁主要是用来解决解决多线程运行访问共享资源时的线程安全问题.那你是不是很好奇,这些Lock锁api是如何实现的呢?本 ...

  6. ArcGIS GDB 文件中的lock文件影响复制

    复制或压缩gdb文件的时候,经常碰到有lock文件,解决方法是: 在catalog中停止相应的地图服务 如果用catalog预览过相应的地图,关闭catalog

  7. T-SQL中的一些小陷阱

    1,当心ISNULL函数对你的逻辑引起BUG 有人喜欢或者习惯于(并不代表我推荐,甚至这种写法没有任何好处)用ISNULL处理变量这种方式写查询 比如:select * from TestISNULL ...

  8. C# 中几个小“陷阱”

    每天写代码,偶尔就会有让你抓狂的时候:代码改了千百遍,蓦然回首,Bug就在灯火阑珊处……这里就列举一些容易犯错的几个小地方,以后遇到了其他的,再慢慢添加.   1. 获取程序当前运行路径   情景复现 ...

  9. IO/ACM中来自浮点数的陷阱(收集向)

    OI/ACM中经常要用到小数来解决问题(概率.计算几何等),但是小数在计算机中的存储方式是浮点数而不是我们在作数学运算中的数,有精度的限制. 以下以GUN C++为准,其他语言(或编译器)也差不了多少 ...

随机推荐

  1. 不同语言的Unix时间戳

    如何在不同编程语言中获取现在的Unix时间戳(Unix timestamp)? Java time JavaScript Math.round(new Date().getTime()/1000)ge ...

  2. POJ 1068 Parencodings

    Parencodings Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 24932   Accepted: 14695 De ...

  3. Oracle EM 不能访问

    zwt2001267 原文 Oracle EM 不能访问 1. cmd控制启动EM: C:\Users\Administrator>emctl start dbconsoleEnvironmen ...

  4. Oracle OCI-22053:溢出错误解决方法

    原文 Oracle OCI-22053:溢出错误解决方法 Oracle 数值数据类型最多可存储 38 个字节的精度.当将 Oracle 数值转换为公共语言运行库数据类型时,小数点后边的位数可能过多,这 ...

  5. Redis常用命令手册:服务器相关命令

    Redis提供了丰富的命令(command)对数据库和各种数据类型进行操作,这些command可以在Linux终端使用.在编程时,比如各类语言包,这些命令都有对应的方法.下面将Redis提供的命令做一 ...

  6. Mysql 多表联合查询效率分析及优化

    1. 多表连接类型 1. 笛卡尔积(交叉连接) 在MySQL中可以为CROSS JOIN或者省略CROSS即JOIN,或者使用','  如: SELECT * FROM table1 CROSS JO ...

  7. Windows 窗体最小化和隐藏的区别及恢复

    应用程序有托盘图标,窗体最小化或者隐藏窗体时,点击托盘图标需要恢复窗体显示,并且恢复之前的现实状体,正常大小或者最大化显示.例如:最大化显示窗体时,点击最小化按钮,窗体最小化,点击托盘图标将最大化显示 ...

  8. UE 使用技巧

    一.关于正则表达式的使用 删除空行: 替换 %[ ^t]++^p 为 空串 替换回车换行符:替换^p 为 空串 删除行尾空格: 替换 [ ^t]+$ 为 空串 删除行首空格: 替换 %[ ^t]+ 为 ...

  9. Fitnesse+RestFixture:Web服务回归测试利器

    RestFixture是Fitness的一个测试REST服务的插件,用于调用标准的http GET/POST等请求方法,并可以用XPath语法和Javascript语法检验http响应.本文介绍安装运 ...

  10. 在虚拟机中安装windows

    前言: 本来在windows当中安装windows是一件很简单的事,但是在使用光盘进行安装的时候,发现无法进行安装. 思路: 将光盘进行提取成iso文件,一个光盘提取一个iso文件,从而存在两个iso ...