Deadlock - How do I know which thread is blocked, preferably using the studio's visual debugger (programming over the network)?

I just use a simple lock to manage some common data.

Is there any way to find out which thread took the lock?

Basically, someone already acquired the lock and did not release it. Thus, all subsequent operations simply hit on locking and timing.

I kind of hit it, because it just flows from the debugger in the lock, because someone had already purchased it, and I looked at "Debugger + Windows + Threads" after "Break All" - not a single nick entered the lock.

It does not show threads that have entered the critical section.

Any help / thoughts appreciated ...

There is a chance that someone took the lock, and this thread was interrupted. But I expect the lock to be released, although the thread was interrupted. Is my expectation wrong?


Here is my class - basically its synergo cmd runner and cmds can be executed from several threads:

internal abstract class PowerShellCommandRunner : IDisposable { #region Fields protected object m_syncObject = new object(); private PSSession m_psSession = null; private Runspace m_runspace = null; #endregion #region Constructor public PowerShellCommandRunner(ExchangeApplicationSystem system) { if (null == system) { throw new ArgumentNullException("ExchangeApplicationSystem"); } this.ExchangeApplicationSystem = system; this.PSCredential = this.ExchangeApplicationSystem.Credential.GetPSCredential(); } #endregion #region Properties internal ExchangeApplicationSystem ExchangeApplicationSystem { get; private set; } public PSCredential PSCredential { get; protected set; } private bool IsNotInitializedOrInvalidRunspace(Runspace runspace) { bool flag = (null == runspace) //not initialized || (null == runspace.RunspaceStateInfo) //not state info (defensive) || (runspace.RunspaceStateInfo.State == RunspaceState.Broken) //runspace state is broken || (null != runspace.RunspaceStateInfo.Reason); //there is an exception return flag; } private bool NeedToCreatePsSession { get { bool flag = (null == this.m_psSession) || this.IsNotInitializedOrInvalidRunspace(this.m_psSession.Runspace); return flag; } } internal Runspace Runspace { get { lock (this.m_syncObject) { if (this.IsNotInitializedOrInvalidRunspace(this.m_runspace)) { if (null != this.m_runspace) { //already have one runspace - close it, before we create another one this.CloseRunspace(); } this.m_runspace = RunspaceFactory.CreateRunspace(); this.m_runspace.Open(); } return this.m_runspace; } } } #endregion #region Methods internal IEnumerable<PSObject> Execute(string cmd, params object[] argumentList) { if (string.IsNullOrEmpty(cmd)) { throw new ArgumentNullException("cmd"); } return this.Execute(new Command(cmd), argumentList); } /// <summary> /// Sub-classes can do their own specific implementation to create ps-sessions /// The base class simply performs primitive oepratiosn like managing them. /// </summary> /// <returns></returns> internal abstract PSSession GetPSSession(); /// <summary> /// Gets the pssession and if reuired updates it as well /// </summary> /// <returns></returns> private PSSession GetAndUpdateManagePSSessionInfRequired() { //Note: we dont need to lock as the callers (Exceute methods) will be acquiring the lock before executing the code //but, just locking it again as the locks are re-entrant lock (this.m_syncObject) { if (this.NeedToCreatePsSession) { if (null != this.m_psSession && (null != this.m_runspace)) { //if ps-session exists, remove it from runspace this.RemovePsSessionFromRunspace(); //Yes, there can be a case where some one already have a reference to the remove session //that ok, as the operation simply throws //And subsequently they will be releasing and re-using the new one. this.m_psSession = null; } //now, open a new session (requesting for a new session from subclasses) this.m_psSession = this.GetPSSession(); Debug.Assert(null != this.m_psSession); } return this.m_psSession; } } internal IEnumerable<PSObject> Execute(Command cmd, params object[] argumentList) { if (null == cmd) { throw new ArgumentNullException("cmd"); } lock (this.m_syncObject) { //Pipelines cannot be executed concurrently, so serialize it OperationProgressReporter.Report(string.Format("Executing the following PowerShell Command: {0}", cmd.ToString())); return this.Runspace.ExecuteCommand(cmd, this.GetAndUpdateManagePSSessionInfRequired(), argumentList); } } internal IEnumerable<PSObject> Execute(ScriptBlock sb, params object[] argumentList) { if (null == sb) { throw new ArgumentNullException("scriptblock"); } lock (this.m_syncObject) { //Pipelines cannot be executed concurrently, so serialize it OperationProgressReporter.Report(string.Format("Executing the following PowerShell Command: {0}", sb.ToString())); return this.Runspace.ExecuteCommand(sb, this.GetAndUpdateManagePSSessionInfRequired(), argumentList); } } private void RemovePsSessionFromRunspace() { //not intended to call before acquiring a lock //(For ex: either while closing runspace or while getting rid of old session and getting a new one (GetAndUpdateManagePSSessionInfRequired) //but locking it as the locks are re-entrant (defensive) lock (this.m_syncObject) { if ((null != this.m_psSession) && (null != this.m_runspace)) { try { string errorMsg = null; this.m_runspace.RemovePsSessionFromRunspace(this.m_psSession, out errorMsg); if (!string.IsNullOrEmpty(errorMsg)) { FxTracing.TraceError(TraceEventId.GeneralError, errorMsg); } } catch (Exception ex) { ExceptionManager.GeneralExceptionFilter(ex); OperationProgressReporter.Report(OperationProgressMessageLevel.Verbose, string.Format("<DEBUG> Unable to remove PSsession from runspace in '{0}'", this.ExchangeApplicationSystem)); } } } } private void CloseRunspace() { //lcok it lock (this.m_syncObject) { //check again to make sure only one thread enters if (null != this.m_runspace) { try { //if a ps-session is created, remove it if (null != this.m_psSession) { //remove the pssession from runspace this.RemovePsSessionFromRunspace(); } //then close the runspace this.m_runspace.Close(); } catch (Exception ex) { //swallow ExceptionManager.GeneralExceptionFilter(ex); Debug.Fail(ex.Message); } finally { //finally, set the runspace to null //Yes, the runspace can be set to null while another thread can have a reference to old runspace //its ok as the operation simply fail with invalid runspace state exception (most likely) //And when they retry they get the updated runspace or get a new one. //same appraoch as managing ps-session this.m_runspace = null; } } } } #endregion #region IDisposable public void Dispose() { this.CloseRunspace(); } #endregion } 

Regards, Dreamer

+4
source share
2 answers

Perhaps this would help:

  • Enable unmanaged debugging (Project Properties> Debugging> check "Enable unmanaged code debugging"
  • Set a breakpoint somewhere
  • When execution is interrupted, in the Immediate window, type: .load sos and enter !SyncBlk -a
+3
source

Just add some diagnostic print messages using Debug.WriteLine to see that the whh stream has entered the critical section.

http://msdn.microsoft.com/en-us/library/system.diagnostics.debug.writeline.aspx

+2
source

Source: https://habr.com/ru/post/1484016/


All Articles