{"record":{"id":"c472f51e33478660","repo":"stride3d/stride","slug":"trying-to-enter-a-lock-that-has-already-been-entered","errorCode":null,"errorMessage":"Trying to enter a lock that has already been entered","messagePattern":"Trying to enter a lock that has already been entered","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Design/MicroThreadLock.cs","lineNumber":143,"sourceCode":"                Release();\n                lock (MicroThreadLock.lockQueue)\n                {\n                    // Remove ourself from the queue.\n                    var thisLock = MicroThreadLock.lockQueue.Dequeue();\n                    if (thisLock != this) throw new InvalidOperationException(\"The first lock in the queue was not the current lock\");\n                    // If another lock is waiting, let's acquire it\n                    if (MicroThreadLock.lockQueue.Count > 0)\n                    {\n                        var nextLock = MicroThreadLock.lockQueue.Peek();\n                        nextLock.Acquire();\n                    }\n                }\n            }\n        }\n\n        internal void Acquire()\n        {\n            if (reentrancy != 0) throw new InvalidOperationException(\"Trying to enter a lock that has already been entered\");\n            ++reentrancy;\n            acquisition.SetResult(0);\n        }\n\n        internal virtual void Reenter()\n        {\n            if (!acquisition.Task.IsCompleted) throw new InvalidOperationException(\"Trying to reenter a lock that has not yet been acquired\");\n            ++reentrancy;\n        }\n\n        internal abstract void Release();\n    }\n\n    private class MicroThreadAsyncLock : MicroThreadLockBase\n    {\n        public MicroThreadAsyncLock(MicroThreadLock microThreadLock)\n            : base(microThreadLock)\n        {","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Design/MicroThreadLock.cs#L125-L161","documentation":"Acquire() sets the lock's reentrancy counter to 1 and completes the acquisition task. If reentrancy is already non-zero the lock is currently held, and acquiring it again from a fresh context would corrupt the ownership model, so an InvalidOperationException is thrown.","triggerScenarios":"Calling Acquire (via AcquireOrEnqueue) on a lock instance that is already acquired and not yet released — e.g. reusing a single MicroThreadLock object for a second concurrent wait, or the queue logic invoking Acquire on a lock that never released.","commonSituations":"Sharing one lock instance across microthreads/tasks that overlap; recreating work items that re-use a stale lock object instead of a new one; race conditions in custom scheduler code that bypasses the queue.","solutions":["Use a fresh MicroThreadLock instance for each independent acquisition.","Let the built-in Lock()/queue mechanism manage acquisition instead of calling Acquire directly.","Ensure the previous holder fully Disposed/released the lock before reacquiring.","If lock contention is intended, enqueue the lock rather than calling Acquire on a held instance."],"exampleFix":"// before\nvar l = new SyncLock();\nl.AcquireOrEnqueue();\nl.AcquireOrEnqueue(); // throws on second use\n// after\nusing (l.Lock()) { /* work */ }\nvar l2 = new SyncLock();\nusing (l2.Lock()) { /* next work */ }","handlingStrategy":"validation","validationCode":"// only acquire when not held\nif (lockObj.Reentrancy == 0) lockObj.Acquire(); // or rely on Lock()/queue mechanism","typeGuard":"bool CanAcquire(MicroThreadLock l) => l.Reentrancy == 0;","tryCatchPattern":"try { lockObj.Acquire(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"already been entered\")) { /* already held: enqueue/wait instead */ }","preventionTips":["Use Lock() scopes rather than raw Acquire","Create a new lock instance per independent wait","Ensure prior holders released before reacquiring"],"tags":["csharp","locking","reentrancy","concurrency"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}