- 浏览: 3049079 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (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 22395(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 3305之前正好发了些帖子是关于CLR里的委托的,然后看到老赵说事件也 ... -
要让CLR挂掉的话(第二弹)……
2009-09-04 03:26 12872(Disclaimer:如果需要转 ... -
要让CLR挂掉的话……
2009-09-02 16:53 4776(Disclaimer:如果需要转载请先与我联系。 作者:Re ... -
趣味编程:函数式链表的快速排序
2009-08-31 08:53 3445(恢复自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 1636原文作者: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 4058在前一帖里,我用到了下面三处Expression.Call() ... -
看到一个关于ref参数与多态的问题,记一下
2009-05-18 10:48 1941刚才读到Alan McGovern的一帖,问为什么形式参数是r ... -
C#的+=运算符两例
2009-05-06 18:18 2032刚偶尔看到了justjavac写的java解惑 - 半斤八两( ... -
Nullable的诡异之处……
2009-04-02 20:52 1829原来Nullable type是null的时候,以它作为被调用 ...
相关推荐
redisson lock和tryLock 分布式锁简单练习
关键字-回车映射-ahk回车映射-左手回车 ;;快捷键x说明 上下左右 ... CapsLock+q 箭头上--防止误触屏-CapsLock+q也映射为箭头上 ;; CapsLock+e 删除键-删除前面的-Backspace ;; CapsLock+r 删除键-删除后面的--Del
标题中的"Capslock++"指的是一个利用AutoHotkey脚本技术改造 Capslock 键的工具,旨在提升用户在计算机操作中的工作效率。Capslock键通常用于切换字母大小写,但通过 Capslock++,我们可以将其功能扩展到更高效的...
error 日志当中的记录: [ERROR] Fatal error: Can’t open and lock privilege tables: Table ‘mysql.host’ doesn’t exist 从发了帖子,只有人看,没有人回复,看到这种情况只能自己解决问题了,自己动手...
"lock(this)的使用说明" lock(this)是C#语言中的一种同步机制,用于确保在多线程环境下对共享资源的访问安全。通过使用lock(this)语句,可以保证在同一时刻只有一个线程可以访问某个资源,防止多个线程同时访问同...
`yarn.lock` 和 `package-lock.json` 文件都是npm和yarn包管理器为了确保项目依赖一致性而生成的文件。本篇文章将详细探讨这两个文件的作用、差异以及如何实现它们之间的相互转换。 ### `yarn.lock` 文件 `yarn....
Lock锁是对象锁,仅在同一对象中,锁才会生效。(不做论证) (以下场景皆为单例模式下运行) lock.lock()的加锁方式,会使后续请求的线程堵塞等待。(方案A) lock.tryLock()的加锁方式,不会堵塞,会立即返回加锁...
pthread_mutex_t lock; pthread_mutex_init(&lock, NULL); ``` 在`lock.cpp`和`lock.h`这两个文件中,`lock.h`可能包含了对外部使用锁的接口声明,而`lock.cpp`则实现了具体的锁操作。例如,一个简单的加锁和解锁...
gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 gradle lock文件清除 ...
`lock`语句是C#中用于实现线程同步的重要工具,主要是为了解决多个线程并发访问共享资源时可能出现的竞争条件(race condition)问题。在描述的场景中,`lock`关键字被用来确保在同一时间只有一个线程可以访问特定的...
在IT行业中,"LockFree"是一种并发编程技术,它的核心思想是避免在多线程环境下使用锁来同步对共享资源的访问。LockFree技术在C# .NET框架中也有广泛的应用,可以显著提高多线程环境下的程序性能,降低死锁和竞态...
然而,在升级到2.0版本的过程中,有些用户可能遇到了需要先安装1.1补丁的问题,这给安装过程带来了一定的困扰。为此,专门设计了一个"lock on 2.0 免1.1补丁",旨在简化安装流程,让玩家能够更顺畅地享受游戏。 这...
4. `spin_lock_bh(spinlock_t *lock)`:与 `spin_lock` 类似,但在获取锁时会禁止软中断。适用于需要在持有锁的同时禁止软中断的场景。 5. `spin_unlock_bh(spinlock_t *lock)`:对应于 `spin_lock_bh` 的解锁操作,...
在C#编程中,`Lock`是一个至关重要的概念,它涉及到多线程编程中的同步控制。`Lock`机制用于确保在任何给定时间只有一个线程可以访问特定的代码块,从而避免了数据竞争和其他并发问题。这个实例将深入探讨`Lock`的...
标题中的“capslock.rar”指的是一个压缩包文件,其中包含了关于Capslock+软件的相关内容。Capslock+是一款创新的工具,它扩展了键盘上通常不常用到的Capslock键的功能,将其转化为一种强大的操作快捷键。这款软件的...
《lock4j高性能分布式锁详解》 分布式锁是分布式系统中的关键组件,它在多节点共享资源时确保了数据的一致性和并发控制。lock4j作为一款高性能的分布式锁,为开发者提供了简单易用且高效的解决方案。本文将深入探讨...
在C#编程语言中,`lock`语句是一种同步机制,用于实现线程之间的互斥访问,确保在多线程环境中资源的安全访问。本篇将深入探讨`lock`的使用,以及它在并发编程中的作用。 `lock`关键字是C#中实现线程同步的关键工具...
### 彻底理解 Oracle 中 Library Cache Lock 的成因与解决办法 #### 一、引言 在日常数据库管理工作中,经常会遇到一些让人头疼的问题,比如会话挂起(hang)。其中一个常见的情况是当用户尝试执行某些操作时,比如...
.NET LOCK使用方法 .NET框架中的Lock关键字用于控制多线程对共享资源的访问,确保在同一时间只有一个线程能够执行一个代码块。当一个线程访问被锁定的资源时,其它所有尝试获取锁的线程将被阻塞,直到锁被释放。 ...