La declaración lock(someObject)
, que es posible que haya llegado a través, es el azúcar sintáctica alrededor Monitor.Enter
y Monitor.Exit
.
Sin embargo, si utiliza el monitor de esta manera más detallada, también puede usar Monitor.TryEnter
que le permite comprobar si podrá obtener el bloqueo, verificando si alguien más ya lo tiene y está ejecutando el código .
Así que en lugar de esto:
var lockObject = new object();
lock(lockObject)
{
// do some stuff
}
probar esto (opción 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);
}
(es probable que desee poner un try..finally allí para asegurar la se libera el bloqueo)
o prescindir del bloqueo explícito y hacer esto
(opción 2)
private int _inUseCount;
public void MyMethod()
{
if (Interlocked.Increment(ref _inUseCount) == 1)
{
// do dome stuff
}
Interlocked.Decrement(ref _inUseCount);
}
[Editar: en respuesta a su pregunta sobre this
]
No - no utilice this
a lock
sucesivamente. Cree un objeto de ámbito privado para actuar como su bloqueo.
De lo contrario, tienen este problema potencial:
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();
}
}
En el ejemplo anterior, un código externo ha logrado interrumpir el bloqueo interno de nuestra clase sólo por tomar un bloqueo de algo que era accesible desde el exterior.
Mucho mejor para crear un objeto privado que controlas, y que nadie fuera de tu clase tenga acceso, para evitar este tipo de problemas; esto incluye no usar this
o el tipo en sí typeof(MyClassWithLockInside)
para bloquear.
¿Sería 'this' ser un cuadro LockObject adecuada? – DerMike
¿Por qué el voto a favor? –
Aceptado para la opción 2 – DerMike