- 浏览: 3014870 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
悲剧啊……前几天有个同学不停问我Java里的同步问题,今天写C#的时候却不小心把lock的语义给弄混了。诶,才回答过的问题换个马甲就把我给绊住了 T T
下午写代码的时候,对某个库的实现有点疑问,就钻进去看了下。然后看到一个方法A里是用lock语句包围的,获取了一个锁,其中调用了一个辅助方法B;B也是被lock语句包围的,要获取了同一个锁。我就纳闷这代码是怎么跑得通的,两个方法要同时获取同一个锁不是阻塞了么?
然后我发现我是把lock跟跟线程无关的简单的flag给弄混了 T T
关键是,lock语句、Mutex和Semaphore都是以线程为单位来获取/释放的,而不是以方法之类的为单位。如果一个方法已经获取了某个锁,它调用另一个方法也要获取同一个锁,那么完全没问题,因为方法调用是在同一个线程上的。
把我看到的代码简化一下,状况如下例所示:
换成Mutex也一样:
我是想像成类似这样了……(嗯我知道Interlocked.Exchange()和Interlocked.CompareExchange()不一样,只是说类似)
这样写的话,“获取”一个锁(也就是把_flag置为1,并且_flag原来的值为0)就不是以线程为单位。于是就死锁了。正常用lock、Mutex、Semaphore不会遇到这种问题……
就算Monitor.Enter里面有用到InterlockedCompareExchange()……Monitor.Enter并不是简单的把SyncBlock里的值在0和1间切换,而是还涉及到线程身份。我一下把这个给忘了,赶紧记下来 TvT
下午写代码的时候,对某个库的实现有点疑问,就钻进去看了下。然后看到一个方法A里是用lock语句包围的,获取了一个锁,其中调用了一个辅助方法B;B也是被lock语句包围的,要获取了同一个锁。我就纳闷这代码是怎么跑得通的,两个方法要同时获取同一个锁不是阻塞了么?
然后我发现我是把lock跟跟线程无关的简单的flag给弄混了 T T
关键是,lock语句、Mutex和Semaphore都是以线程为单位来获取/释放的,而不是以方法之类的为单位。如果一个方法已经获取了某个锁,它调用另一个方法也要获取同一个锁,那么完全没问题,因为方法调用是在同一个线程上的。
把我看到的代码简化一下,状况如下例所示:
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; static class Program { static void Main(string[] args) { var foo = new ArrayWrapper<string>(); foo.TrySetValue(2, "Charlie"); foo.TrySetValue(0, "Alpha"); foreach (var str in foo) { Console.WriteLine(str); } } } class ArrayWrapper<T> : IEnumerable<T>, IEnumerable { readonly object LockObject; T[] _data; public ArrayWrapper() { LockObject = new object(); _data = new T[0]; } public void TrySetValue(int index, T value) { lock (LockObject) { Console.WriteLine("acquired lock in TrySetValue"); var data = _data; if (index < 0) return; if (index >= data.Length) { data = PromoteData(data.Length, index + 1); } data[index] = value; } } private T[] PromoteData(int oldLen, int newLen) { Debug.Assert(oldLen != newLen); lock (LockObject) { Console.WriteLine("acquired lock in PromoteData"); if (_data.Length == oldLen) { var data = new T[newLen]; _data.CopyTo(data, 0); _data = data; } return _data; } } public IEnumerator<T> GetEnumerator() { var data = _data; foreach (var item in data) { yield return item; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
换成Mutex也一样:
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Threading; static class Program { static void Main(string[] args) { var foo = new ArrayWrapper<string>(); foo.TrySetValue(2, "Charlie"); foo.TrySetValue(0, "Alpha"); foreach (var str in foo) { Console.WriteLine(str); } } } class ArrayWrapper<T> : IEnumerable<T>, IEnumerable { readonly Mutex _mutex; T[] _data; public ArrayWrapper() { _mutex = new Mutex(); _data = new T[0]; } public void TrySetValue(int index, T value) { _mutex.WaitOne(); Console.WriteLine("acquired mutex in TrySetValue"); var data = _data; if (index < 0) return; if (index >= data.Length) { data = PromoteData(data.Length, index + 1); } data[index] = value; _mutex.ReleaseMutex(); } private T[] PromoteData(int oldLen, int newLen) { Debug.Assert(oldLen != newLen); _mutex.WaitOne(); Console.WriteLine("acquired mutex in PromoteData"); T[] data = _data; if (_data.Length == oldLen) { data = new T[newLen]; _data.CopyTo(data, 0); _data = data; } _mutex.ReleaseMutex(); return data; } public IEnumerator<T> GetEnumerator() { var data = _data; foreach (var item in data) { yield return item; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
我是想像成类似这样了……(嗯我知道Interlocked.Exchange()和Interlocked.CompareExchange()不一样,只是说类似)
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Threading; static class Program { static void Main(string[] args) { var foo = new ArrayWrapper<string>(); foo.TrySetValue(2, "Charlie"); foo.TrySetValue(0, "Alpha"); foreach (var str in foo) { Console.WriteLine(str); } } } class ArrayWrapper<T> : IEnumerable<T>, IEnumerable { int _flag; T[] _data; public ArrayWrapper() { _flag = 0; _data = new T[0]; } public void TrySetValue(int index, T value) { var done = false; while (!done) { // spin on the lock Console.WriteLine("trying to acquire lock in TrySetValue"); if (0 == Interlocked.Exchange(ref _flag, 1)) { Console.WriteLine("acquired mutex in TrySetValue"); var data = _data; if (index < 0) return; if (index >= data.Length) { data = PromoteData(data.Length, index + 1); } data[index] = value; done = true; Interlocked.Exchange(ref _flag, 0); } if (!done) Thread.Sleep(500); } } private T[] PromoteData(int oldLen, int newLen) { Debug.Assert(oldLen != newLen); T[] data = null; var done = false; while (!done) { // spin on the lock Console.WriteLine("trying to acquire lock in PromoteData"); if (0 == Interlocked.Exchange(ref _flag, 1)) { Console.WriteLine("acquired mutex in PromoteData"); data = _data; if (_data.Length == oldLen) { data = new T[newLen]; _data.CopyTo(data, 0); _data = data; } done = true; Interlocked.Exchange(ref _flag, 0); } if (!done) Thread.Sleep(500); } return data; } public IEnumerator<T> GetEnumerator() { var data = _data; foreach (var item in data) { yield return item; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
这样写的话,“获取”一个锁(也就是把_flag置为1,并且_flag原来的值为0)就不是以线程为单位。于是就死锁了。正常用lock、Mutex、Semaphore不会遇到这种问题……
就算Monitor.Enter里面有用到InterlockedCompareExchange()……Monitor.Enter并不是简单的把SyncBlock里的值在0和1间切换,而是还涉及到线程身份。我一下把这个给忘了,赶紧记下来 TvT
发表评论
-
字符串的一般封装方式的内存布局 (1): 元数据与字符串内容,整体还是分离?
2013-11-07 17:44 22245(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局
2013-11-01 12:55 0(Disclaimer:未经许可请 ... -
关于string,内存布局,C++ std::string,CoW
2013-10-30 20:45 0(Disclaimer:未经许可请 ... -
对象的重量
2011-08-21 17:15 0http://domino.research.ibm.com/ ... -
GetCustomAttribute()每次都返回新Attribute实例
2009-11-10 10:30 0Jeffrey Zhao: 一次失败的尝试(上):原来GetC ... -
委托与方法和隐藏参数
2009-09-07 15:32 3242之前正好发了些帖子是关于CLR里的委托的,然后看到老赵说事件也 ... -
要让CLR挂掉的话(第二弹)……
2009-09-04 03:26 12760(Disclaimer:如果需要转 ... -
要让CLR挂掉的话……
2009-09-02 16:53 4691(Disclaimer:如果需要转载请先与我联系。 作者:Re ... -
趣味编程:函数式链表的快速排序
2009-08-31 08:53 3370(恢复自2009-08-28的备份 ... -
事件处理器导致内存泄漏
2009-08-25 15:03 0Memory leak via event handlers ... -
C# 3.0的类型推导
2009-08-23 12:24 0Howard Dierking: Lambda, Lambda ... -
把IEnumerable<T>和IObservable<T>粘起来?
2009-07-23 03:02 0Channel 9: Expert to Expert: Br ... -
Scott Peterson: Variance, Thy Name is Ambiguity
2009-07-01 23:49 1586原文作者:Scott Peterson 原文地址:http:/ ... -
void无法协变
2009-06-30 11:17 0Eric Lippert The void is invari ... -
同一个表达式算出来的浮点数结果会不相等?
2009-05-30 03:27 0浮点数有很多可把玩的地方。例如下面这段C程序: #includ ... -
C#开始默认引用Microsoft.CSharp.dll
2009-05-20 16:14 0记得VB6的运行时么?留意到VB.NET的程序都需要额外的VB ... -
反射与显式实现接口的方法
2009-05-20 11:43 4000在前一帖里,我用到了下面三处Expression.Call() ... -
看到一个关于ref参数与多态的问题,记一下
2009-05-18 10:48 1908刚才读到Alan McGovern的一帖,问为什么形式参数是r ... -
C#的+=运算符两例
2009-05-06 18:18 1971刚偶尔看到了justjavac写的java解惑 - 半斤八两( ... -
Nullable的诡异之处……
2009-04-02 20:52 1785原来Nullable type是null的时候,以它作为被调用 ...
相关推荐
redisson lock和tryLock 分布式锁简单练习
关键字-回车映射-ahk回车映射-左手回车 ;;快捷键x说明 上下左右 ... CapsLock+q 箭头上--防止误触屏-CapsLock+q也映射为箭头上 ;; CapsLock+e 删除键-删除前面的-Backspace ;; CapsLock+r 删除键-删除后面的--Del
Lock锁是对象锁,仅在同一对象中,锁才会生效。(不做论证) (以下场景皆为单例模式下运行) lock.lock()的加锁方式,会使后续请求的线程堵塞等待。(方案A) lock.tryLock()的加锁方式,不会堵塞,会立即返回加锁...
Lock
gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 ...
设定CapsLock ScrollLock NumLock
oracle lock资料
实现yarn.lock与package-lock.json相互转换
Capslock+软件下载http://cjkis.me/capslock+/
php lock for php file
lockfree JmBucknall.Structures
significance of a lock-in amplifier. As an introduction to the subject there follows a simple intuitive account biased towards light measurement applications. All lock-in amplifiers, whether ...
所以 PowerManager.WakeLock 的计数机制并不是正真意义上的对每次请求进行申请/释放每一把锁,它只是对同一把锁被申请/释放的次数进行了统计,然后再去操作。 源码 位置:frameworks/base/core/java/android/os/...
dblock.zip
java多线程之lock。 Lock的基本用法如下,为了防止异常退出时没有释放锁,一般都在拿到锁后立马try,try住所有临界区的代码,然后finally释放锁。
lock 使用演示代码,让大家认识到LOCK的用途
Capslock++(AutoHotKey脚本),改造Capslock键,快速提升工作效率
Lock SELinux forced mode.zip
打开numlock灯
Capslock+利用了键盘少用的Capslock键,实现了很多强大的操作。 Capslock+是开源的,源码在Github上,https://cjkis.me/capslock+/官网及帮助