非阻塞锁 [英] Non blocking locking
问题描述
我要开始新的一些新的主题进行一个重复操作。但是,当这样的操作已经在进行中,我想放弃当前任务。在我的情况,我需要非常当前的数据只是 - 下降的数据是不是一个问题。
。在MSDN,我发现了互斥
类,但据我所知,它等待轮到它,阻止当前线程。此外,我要问你:的东西是否存在已经是.NET框架,即做以下
- 在一些子程序M已经被执行?
- 如果是这样,
返回
(让我增加一些反统计) - 如果没有,启动方法M在一个新的线程
在锁(someObject)
语句,你可能会遇到的,是语法左右<$糖C C> Monitor.Enter 和 Monitor.Exit
。
不过,如果您使用的显示器在此更详细的方法,你也可以使用 Monitor.TryEnter
,它允许你检查你就可以得到锁定 - 因此,检查是否有人已经拥有它,并正在执行code
所以:
VAR lockObject =新的对象();
锁定(lockObject)
{
//做一些东西
}
试试这个(选项1)
INT _alreadyBeingExecutedCounter;
VAR lockObject =新的对象();
如果(Monitor.TryEnter(lockObject))
{
//你只在这里结束,如果你得到了锁,当你试图得到它 - 否则,你永远也不会执行该code。
//做一些东西
//调用exit释放锁
Monitor.Exit(lockObject);
}
其他
{
//没有得到锁 - 别人正在执行的code以上 - 所以我不需要做任何工作!
Interlocked.Increment(REF _alreadyBeingExecutedCounter);
}
(你可能会希望把一个try..finally在那里,以确保锁被释放)
或免除明确锁定althogether而做到这一点
(选项2)
私人诠释_inUseCount;
公共无效的MyMethod()
{
如果(Interlocked.Increment(参考_inUseCount)== 1)
{
//做穹顶东西
}
Interlocked.Decrement(REF _inUseCount);
}
没有 - 不使用这
到上锁定
。创建一个私人范围的对象作为你的锁。
否则,你有这个潜在的问题:
公共类MyClassWithLockInside
{
公共无效MethodThatTakesLock()
{
锁(本)
{
//做一些工作
}
}
}
公共类消费
{
私有静态MyClassWithLockInside _instance =新MyClassWithLockInside();
公共无效ThreadACallsThis()
{
锁(_instance)
{
//已经采取了锁在我们的MyClassWithLockInside的情况下,
//做一些长时间运行
Thread.sleep代码(6000);
}
}
公共无效ThreadBCallsThis()
{
//如果线程B调用此同时,线程A仍然是内锁上面,
//因为它试图对同一对象获取锁定这个方法会阻塞
// [本之类的内部= _instance外]
_instance.MethodThatTakesLock();
}
}
在上面的例子中,一些外部code已设法破坏我们类的内部锁定只是通过取出的东西的锁定,这是外部可访问的
最好创建你控制一个私有对象,而且没有一类的外部访问,以避免这些类型的问题;这包括不使用这
或类型本身的typeof(MyClassWithLockInside)
锁定。
I want to start some new threads each for one repeating operation. But when such an operation is already in progress, I want to discard the current task. In my scenario I need very current data only - dropped data is not an issue.
In the MSDN I found the Mutex
class but as I understand it, it waits for its turn, blocking the current thread. Also I want to ask you: Does something exist in the .NET framework already, that does the following:
- Is some method M already being executed?
- If so,
return
(and let me increase some counter for statistics) - If not, start method M in a new thread
The lock(someObject)
statement, which you may have come across, is syntactic sugar around Monitor.Enter
and Monitor.Exit
.
However, if you use the monitor in this more verbose way, you can also use Monitor.TryEnter
which allows you to check if you'll be able to get the lock - hence checking if someone else already has it and is executing code.
So instead of this:
var lockObject = new object();
lock(lockObject)
{
// do some stuff
}
try this (option 1):
int _alreadyBeingExecutedCounter;
var lockObject = new object();
if (Monitor.TryEnter(lockObject))
{
// you'll only end up here if you got the lock when you tried to get it - otherwise you'll never execute this code.
// do some stuff
//call exit to release the lock
Monitor.Exit(lockObject);
}
else
{
// didn't get the lock - someone else was executing the code above - so I don't need to do any work!
Interlocked.Increment(ref _alreadyBeingExecutedCounter);
}
(you'll probably want to put a try..finally in there to ensure the lock is released)
or dispense with the explicit lock althogether and do this
(option 2)
private int _inUseCount;
public void MyMethod()
{
if (Interlocked.Increment(ref _inUseCount) == 1)
{
// do dome stuff
}
Interlocked.Decrement(ref _inUseCount);
}
[Edit: in response to your question about this
]
No - don't use this
to lock
on. Create a privately scoped object to act as your lock.
Otherwise you have this potential problem:
public class MyClassWithLockInside
{
public void MethodThatTakesLock()
{
lock(this)
{
// do some work
}
}
}
public class Consumer
{
private static MyClassWithLockInside _instance = new MyClassWithLockInside();
public void ThreadACallsThis()
{
lock(_instance)
{
// Having taken a lock on our instance of MyClassWithLockInside,
// do something long running
Thread.Sleep(6000);
}
}
public void ThreadBCallsThis()
{
// If thread B calls this while thread A is still inside the lock above,
// this method will block as it tries to get a lock on the same object
// ["this" inside the class = _instance outside]
_instance.MethodThatTakesLock();
}
}
In the above example, some external code has managed to disrupt the internal locking of our class just by taking out a lock on something that was externally accessible.
Much better to create a private object that you control, and that no-one outside your class has access to, to avoid these sort of problems; this includes not using this
or the type itself typeof(MyClassWithLockInside)
for locking.
这篇关于非阻塞锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!