¿Por qué el hilo no está interrumpido cuando se duerme? -- # campo con multithreading campo con interrupted-exception camp Relacionados El problema

Why is thread not interrupted when sleeping in finally block


9
vote

problema

Español

He estado mirando por todo MSDN y no puedo encontrar una razón por la cual el hilo no se puede interrumpir cuando se duerme dentro finalmente. He intentado abortar sin éxito.

¿Hay alguna forma en cómo despertar el hilo al dormir dentro de finalmente bloquear?

  Thread t = new Thread(ProcessSomething) {IsBackground = false}; t.Start(); Thread.Sleep(500); t.Interrupt(); t.Join();  private static void ProcessSomething() {     try { Console.WriteLine("processing"); }     finally     {         try         {             Thread.Sleep(Timeout.Infinite);         }         catch (ThreadInterruptedException ex)         {             Console.WriteLine(ex.Message);         }     } }   

Sorprendentemente, el hilo de las reclamaciones de MSDN se puede abortar en Finalmente Bloquear: http://msdn.microsoft.com/en-us/library/aa332364 (v = vs.71) .aspx "Hay una posibilidad de que el hilo pueda abortar mientras finalmente se está bloqueando un bloque, en cuyo caso se aborta el bloque finalmente."

editar Encuentro a Hans Passant Comment como la mejor respuesta, ya que esto explica por qué el hilo a veces puede y no puede ser interrumpido / abortado en el bloqueo finalmente. Y eso es cuando el proceso se apaga. gracias

Original en ingles

I have been looking all over MSDN and can't find a reason why Thread can not be interrupted when sleeping within finally block. I have tried aborting with no success.

Is there any way how to wake up thread when sleeping within finally block?

Thread t = new Thread(ProcessSomething) {IsBackground = false}; t.Start(); Thread.Sleep(500); t.Interrupt(); t.Join();  private static void ProcessSomething() {     try { Console.WriteLine("processing"); }     finally     {         try         {             Thread.Sleep(Timeout.Infinite);         }         catch (ThreadInterruptedException ex)         {             Console.WriteLine(ex.Message);         }     } } 

Surprisingly MSDN claims thread CAN be aborted in finally block: http://msdn.microsoft.com/en-us/library/aa332364(v=vs.71).aspx "There is a chance the thread could abort while a finally block is running, in which case the finally block is aborted."

edit I find Hans Passant comment as best answer since this explains why Thread sometimes can and can not be interrupted/aborted in finally block. And that is when process is shutting down. thanks

        
         
         

Lista de respuestas

9
 
vote
vote
La mejor respuesta
 

Deben evitarse el abortamiento e interrupción de los hilos si es posible, ya que esto puede corromper el estado de un programa en ejecución. Por ejemplo, imagine que abortó un hilo que sostenía las cerraduras abiertas a los recursos, estos bloqueos nunca serían liberados.

En su lugar, considere usar un mecanismo de señalización para que las roscas puedan cooperar entre sí y, por lo tanto, manejar el bloqueo y desbloquear con gracia, por ejemplo,

      private readonly AutoResetEvent ProcessEvent = new AutoResetEvent(false);     private readonly AutoResetEvent WakeEvent = new AutoResetEvent(false);      public void Do()     {         Thread th1 = new Thread(ProcessSomething);         th1.IsBackground = false;         th1.Start();          ProcessEvent.WaitOne();          Console.WriteLine("Processing started...");          Thread th2 = new Thread(() => WakeEvent.Set());         th2.Start();          th1.Join();         Console.WriteLine("Joined");     }      private void ProcessSomething()     {         try         {             Console.WriteLine("Processing...");             ProcessEvent.Set();         }         finally         {             WakeEvent.WaitOne();             Console.WriteLine("Woken up...");         }     }   

actualización

un problema bastante interesante de bajo nivel. Aunque Abort() está documentado, Interrupt() es mucho menos.

La respuesta corta a su pregunta es No, no puede despertar un hilo en un bloque Finalmente llamando Abort o 9988777668 en él.

No poder cancelar o interrumpir los hilos en finalmente los bloques es por diseño, simplemente para que finalmente los bloqueos tengan la oportunidad de ejecutarse como lo espere. Si pudiera abortar y interrumpir los hilos en los bloques finalmente, esto podría tener consecuencias involuntarias para las rutinas de limpieza, y así abandonar la aplicación en un estado dañado, no es bueno.

Un ligero matiz con interrupción de hilo, es que se puede haber emitido una interrupción contra el hilo en cualquier momento antes de ingresar el bloque final, pero mientras que no estaba en un estado Interrupt()9 (es decir, no bloqueado ). En este caso, si hubiera una llamada de bloqueo en el bloque Finalmente, lanzaría inmediatamente un Public Function Upload(ByVal fi As FileInfo, Optional ByVal targetFilename As String = "") As Boolean 'copy the file specified to target file: target file can be full path or just filename (uses current dir) '1. check target Dim target As String If targetFilename.Trim = "" Then 'Blank target: use source filename & current dir target = GetCurrentUrl() & "/" & fi.Name Else 'otherwise treat as filename only, use current directory target = GetCurrentUrl() & "/" & targetFilename End If Dim URI As String = target 'GetCurrentUrl() & "/" & target 'perform copy Dim ftp As Net.FtpWebRequest = GetRequest(URI) 'Set request to upload a file in binary ftp.Method = Net.WebRequestMethods.Ftp.UploadFile ftp.UseBinary = True 'Notify FTP of the expected size ftp.ContentLength = fi.Length 'create byte array to store: ensure at least 1 byte! Const BufferSize As Integer = 2048 Dim content(BufferSize - 1) As Byte, dataRead As Integer 'open file for reading Using fs As FileStream = fi.OpenRead() Try 'open request to send Using rs As Stream = ftp.GetRequestStream Dim totBytes As Long = 0 Do dataRead = fs.Read(content, 0, BufferSize) rs.Write(content, 0, dataRead) totBytes += dataRead RaiseEvent StatusChanged(totBytes.ToString() & " bytes sent...") Loop Until dataRead < BufferSize rs.Close() RaiseEvent StatusChanged("File uploaded successfully") End Using Catch ex As Exception RaiseEvent StatusChanged("Error: " & ex.Message) Finally 'ensure file closed fs.Close() End Try End Using ftp = Nothing Return True End Function 0 y se bloquearía del bloque Finalmente. Finalmente, la protección de bloques previene esto.

Además de la protección en los bloques finalmente, esto se extiende para probar bloques y también cers ( Región de ejecución restringida ) que se puede configurar en el código de usuario para evitar que se lanza un rango de excepciones hasta después de que se ejecute una región, muy útil para bloques críticos de código que deben completarse y retrasar abortos.

La excepción (sin juego de palabras) a esto es lo que se llama Rude Aborts . Estos son Public Function Upload(ByVal fi As FileInfo, Optional ByVal targetFilename As String = "") As Boolean 'copy the file specified to target file: target file can be full path or just filename (uses current dir) '1. check target Dim target As String If targetFilename.Trim = "" Then 'Blank target: use source filename & current dir target = GetCurrentUrl() & "/" & fi.Name Else 'otherwise treat as filename only, use current directory target = GetCurrentUrl() & "/" & targetFilename End If Dim URI As String = target 'GetCurrentUrl() & "/" & target 'perform copy Dim ftp As Net.FtpWebRequest = GetRequest(URI) 'Set request to upload a file in binary ftp.Method = Net.WebRequestMethods.Ftp.UploadFile ftp.UseBinary = True 'Notify FTP of the expected size ftp.ContentLength = fi.Length 'create byte array to store: ensure at least 1 byte! Const BufferSize As Integer = 2048 Dim content(BufferSize - 1) As Byte, dataRead As Integer 'open file for reading Using fs As FileStream = fi.OpenRead() Try 'open request to send Using rs As Stream = ftp.GetRequestStream Dim totBytes As Long = 0 Do dataRead = fs.Read(content, 0, BufferSize) rs.Write(content, 0, dataRead) totBytes += dataRead RaiseEvent StatusChanged(totBytes.ToString() & " bytes sent...") Loop Until dataRead < BufferSize rs.Close() RaiseEvent StatusChanged("File uploaded successfully") End Using Catch ex As Exception RaiseEvent StatusChanged("Error: " & ex.Message) Finally 'ensure file closed fs.Close() End Try End Using ftp = Nothing Return True End Function 1111 planteado por el propio entorno de alojamiento de CLR. Estos pueden causar finalmente y atrapar bloques que deben salir, pero no cers. Por ejemplo, el CLR puede elevar los abortos groseros en respuesta a los hilos que ha considerado que se está llevando demasiado tiempo para hacer su trabajo Salir E.G. Al intentar descargar un código de aplicaciones o ejecutar un código dentro del SQL Server CLR. En su ejemplo particular, cuando su aplicación se apague y la aplicación se descarga, el CLR emitiría un abortío grosero en el hilo para dormir, ya que habría un tiempo de espera de descarga de AppMomain.

Abortar y interrumpir en finalmente los bloques no va a suceder en el código de usuario, pero hay un comportamiento ligeramente diferente entre los dos casos.

Abort

Cuando llame Public Function Upload(ByVal fi As FileInfo, Optional ByVal targetFilename As String = "") As Boolean 'copy the file specified to target file: target file can be full path or just filename (uses current dir) '1. check target Dim target As String If targetFilename.Trim = "" Then 'Blank target: use source filename & current dir target = GetCurrentUrl() & "/" & fi.Name Else 'otherwise treat as filename only, use current directory target = GetCurrentUrl() & "/" & targetFilename End If Dim URI As String = target 'GetCurrentUrl() & "/" & target 'perform copy Dim ftp As Net.FtpWebRequest = GetRequest(URI) 'Set request to upload a file in binary ftp.Method = Net.WebRequestMethods.Ftp.UploadFile ftp.UseBinary = True 'Notify FTP of the expected size ftp.ContentLength = fi.Length 'create byte array to store: ensure at least 1 byte! Const BufferSize As Integer = 2048 Dim content(BufferSize - 1) As Byte, dataRead As Integer 'open file for reading Using fs As FileStream = fi.OpenRead() Try 'open request to send Using rs As Stream = ftp.GetRequestStream Dim totBytes As Long = 0 Do dataRead = fs.Read(content, 0, BufferSize) rs.Write(content, 0, dataRead) totBytes += dataRead RaiseEvent StatusChanged(totBytes.ToString() & " bytes sent...") Loop Until dataRead < BufferSize rs.Close() RaiseEvent StatusChanged("File uploaded successfully") End Using Catch ex As Exception RaiseEvent StatusChanged("Error: " & ex.Message) Finally 'ensure file closed fs.Close() End Try End Using ftp = Nothing Return True End Function 2 en un hilo en un bloque Finalmente, el hilo de llamada está bloqueado. Esto es documentado :

El hilo que llama al abort puede bloquear si el hilo que se está abortando está en una región de código protegida, como un bloque de captura, finalmente bloquea, o una región de ejecución restringida.

en el caso de abortar si el sueño no era infinito:

  1. El hilo de llamada emitirá un Public Function Upload(ByVal fi As FileInfo, Optional ByVal targetFilename As String = "") As Boolean 'copy the file specified to target file: target file can be full path or just filename (uses current dir) '1. check target Dim target As String If targetFilename.Trim = "" Then 'Blank target: use source filename & current dir target = GetCurrentUrl() & "/" & fi.Name Else 'otherwise treat as filename only, use current directory target = GetCurrentUrl() & "/" & targetFilename End If Dim URI As String = target 'GetCurrentUrl() & "/" & target 'perform copy Dim ftp As Net.FtpWebRequest = GetRequest(URI) 'Set request to upload a file in binary ftp.Method = Net.WebRequestMethods.Ftp.UploadFile ftp.UseBinary = True 'Notify FTP of the expected size ftp.ContentLength = fi.Length 'create byte array to store: ensure at least 1 byte! Const BufferSize As Integer = 2048 Dim content(BufferSize - 1) As Byte, dataRead As Integer 'open file for reading Using fs As FileStream = fi.OpenRead() Try 'open request to send Using rs As Stream = ftp.GetRequestStream Dim totBytes As Long = 0 Do dataRead = fs.Read(content, 0, BufferSize) rs.Write(content, 0, dataRead) totBytes += dataRead RaiseEvent StatusChanged(totBytes.ToString() & " bytes sent...") Loop Until dataRead < BufferSize rs.Close() RaiseEvent StatusChanged("File uploaded successfully") End Using Catch ex As Exception RaiseEvent StatusChanged("Error: " & ex.Message) Finally 'ensure file closed fs.Close() End Try End Using ftp = Nothing Return True End Function 3 , pero bloqueará aquí hasta que finalmente se salga el bloqueo, es decir, se detiene aquí y no se pasa inmediatamente a la declaración Interrupt()1414 .
  2. El hilo de Callee tiene su estado establecido en Public Function Upload(ByVal fi As FileInfo, Optional ByVal targetFilename As String = "") As Boolean 'copy the file specified to target file: target file can be full path or just filename (uses current dir) '1. check target Dim target As String If targetFilename.Trim = "" Then 'Blank target: use source filename & current dir target = GetCurrentUrl() & "/" & fi.Name Else 'otherwise treat as filename only, use current directory target = GetCurrentUrl() & "/" & targetFilename End If Dim URI As String = target 'GetCurrentUrl() & "/" & target 'perform copy Dim ftp As Net.FtpWebRequest = GetRequest(URI) 'Set request to upload a file in binary ftp.Method = Net.WebRequestMethods.Ftp.UploadFile ftp.UseBinary = True 'Notify FTP of the expected size ftp.ContentLength = fi.Length 'create byte array to store: ensure at least 1 byte! Const BufferSize As Integer = 2048 Dim content(BufferSize - 1) As Byte, dataRead As Integer 'open file for reading Using fs As FileStream = fi.OpenRead() Try 'open request to send Using rs As Stream = ftp.GetRequestStream Dim totBytes As Long = 0 Do dataRead = fs.Read(content, 0, BufferSize) rs.Write(content, 0, dataRead) totBytes += dataRead RaiseEvent StatusChanged(totBytes.ToString() & " bytes sent...") Loop Until dataRead < BufferSize rs.Close() RaiseEvent StatusChanged("File uploaded successfully") End Using Catch ex As Exception RaiseEvent StatusChanged("Error: " & ex.Message) Finally 'ensure file closed fs.Close() End Try End Using ftp = Nothing Return True End Function 5 .
  3. El callee continúa durmiendo.
  4. Cuando el callee se despierta, ya que tiene un estado de Public Function Upload(ByVal fi As FileInfo, Optional ByVal targetFilename As String = "") As Boolean 'copy the file specified to target file: target file can be full path or just filename (uses current dir) '1. check target Dim target As String If targetFilename.Trim = "" Then 'Blank target: use source filename & current dir target = GetCurrentUrl() & "/" & fi.Name Else 'otherwise treat as filename only, use current directory target = GetCurrentUrl() & "/" & targetFilename End If Dim URI As String = target 'GetCurrentUrl() & "/" & target 'perform copy Dim ftp As Net.FtpWebRequest = GetRequest(URI) 'Set request to upload a file in binary ftp.Method = Net.WebRequestMethods.Ftp.UploadFile ftp.UseBinary = True 'Notify FTP of the expected size ftp.ContentLength = fi.Length 'create byte array to store: ensure at least 1 byte! Const BufferSize As Integer = 2048 Dim content(BufferSize - 1) As Byte, dataRead As Integer 'open file for reading Using fs As FileStream = fi.OpenRead() Try 'open request to send Using rs As Stream = ftp.GetRequestStream Dim totBytes As Long = 0 Do dataRead = fs.Read(content, 0, BufferSize) rs.Write(content, 0, dataRead) totBytes += dataRead RaiseEvent StatusChanged(totBytes.ToString() & " bytes sent...") Loop Until dataRead < BufferSize rs.Close() RaiseEvent StatusChanged("File uploaded successfully") End Using Catch ex As Exception RaiseEvent StatusChanged("Error: " & ex.Message) Finally 'ensure file closed fs.Close() End Try End Using ftp = Nothing Return True End Function 6 continuará ejecutando el código de bloques finalmente y luego "evaporarse" I.E. Salida.
  5. Cuando el hilo abortado deja el bloque finalmente: no se eleva ninguna excepción, no se ejecuta ningún código después de que finalmente se ejecute el bloque final, y el estado del hilo es 99887776617 .
  6. El hilo de llamada está desbloqueado, continúa con la instrucción Public Function Upload(ByVal fi As FileInfo, Optional ByVal targetFilename As String = "") As Boolean 'copy the file specified to target file: target file can be full path or just filename (uses current dir) '1. check target Dim target As String If targetFilename.Trim = "" Then 'Blank target: use source filename & current dir target = GetCurrentUrl() & "/" & fi.Name Else 'otherwise treat as filename only, use current directory target = GetCurrentUrl() & "/" & targetFilename End If Dim URI As String = target 'GetCurrentUrl() & "/" & target 'perform copy Dim ftp As Net.FtpWebRequest = GetRequest(URI) 'Set request to upload a file in binary ftp.Method = Net.WebRequestMethods.Ftp.UploadFile ftp.UseBinary = True 'Notify FTP of the expected size ftp.ContentLength = fi.Length 'create byte array to store: ensure at least 1 byte! Const BufferSize As Integer = 2048 Dim content(BufferSize - 1) As Byte, dataRead As Integer 'open file for reading Using fs As FileStream = fi.OpenRead() Try 'open request to send Using rs As Stream = ftp.GetRequestStream Dim totBytes As Long = 0 Do dataRead = fs.Read(content, 0, BufferSize) rs.Write(content, 0, dataRead) totBytes += dataRead RaiseEvent StatusChanged(totBytes.ToString() & " bytes sent...") Loop Until dataRead < BufferSize rs.Close() RaiseEvent StatusChanged("File uploaded successfully") End Using Catch ex As Exception RaiseEvent StatusChanged("Error: " & ex.Message) Finally 'ensure file closed fs.Close() End Try End Using ftp = Nothing Return True End Function 8 e inmediatamente pasa a medida que se ha salido el hilo llamado.

Entonces, dado su ejemplo con un sueño infinito, el hilo de llamada bloqueará para siempre en el paso 1.

interrupción

en la caja de interrupción Si el sueño no fue infinito:

no tan bien documentado ...

  1. El hilo de llamada emitirá un Public Function Upload(ByVal fi As FileInfo, Optional ByVal targetFilename As String = "") As Boolean 'copy the file specified to target file: target file can be full path or just filename (uses current dir) '1. check target Dim target As String If targetFilename.Trim = "" Then 'Blank target: use source filename & current dir target = GetCurrentUrl() & "/" & fi.Name Else 'otherwise treat as filename only, use current directory target = GetCurrentUrl() & "/" & targetFilename End If Dim URI As String = target 'GetCurrentUrl() & "/" & target 'perform copy Dim ftp As Net.FtpWebRequest = GetRequest(URI) 'Set request to upload a file in binary ftp.Method = Net.WebRequestMethods.Ftp.UploadFile ftp.UseBinary = True 'Notify FTP of the expected size ftp.ContentLength = fi.Length 'create byte array to store: ensure at least 1 byte! Const BufferSize As Integer = 2048 Dim content(BufferSize - 1) As Byte, dataRead As Integer 'open file for reading Using fs As FileStream = fi.OpenRead() Try 'open request to send Using rs As Stream = ftp.GetRequestStream Dim totBytes As Long = 0 Do dataRead = fs.Read(content, 0, BufferSize) rs.Write(content, 0, dataRead) totBytes += dataRead RaiseEvent StatusChanged(totBytes.ToString() & " bytes sent...") Loop Until dataRead < BufferSize rs.Close() RaiseEvent StatusChanged("File uploaded successfully") End Using Catch ex As Exception RaiseEvent StatusChanged("Error: " & ex.Message) Finally 'ensure file closed fs.Close() End Try End Using ftp = Nothing Return True End Function 9 y continúe ejecutando.
  2. El hilo de llamadas se bloqueará en la declaración protected void Button1_Click(object sender, EventArgs e) { string server = "-------"; //your ip address string ftpPath = "ftp://" + server + "//Files//" +FileUpload1.FileName; string uname = "-----"; string password = "----------"; string filePath = Server.MapPath("~") + "\" + FileUpload1.FileName; try { UploadToFTP(ftpPath,filePath,uname,password); } catch (Exception ex) { //logic here } } 0 .
  3. El hilo de Callee tiene su estado establecido para plantear una excepción en la siguiente llamada de bloqueo, pero de manera crucial, ya que está en un bloque final, no se desbloquee. Ked I.E. Woken.
  4. El callee continúa durmiendo.
  5. Cuando el callee se despierta, continuará ejecutando el bloque final.
  6. Cuando el hilo interrumpido deja el bloque final, lanzará un Interrupt()21 en su siguiente llamada de bloqueo (consulte el ejemplo del código de código a continuación).
  7. El hilo de llamada "se une" y continúa a medida que el hilo llamado se ha salido, sin embargo, el Interrupt()2222 en el paso 6 ha aplanado el proceso ...

Así que nuevamente dado su ejemplo con un sueño infinito, el hilo de llamada se bloqueará para siempre, pero en el Paso 2.

Resumen

Aunque protected void Button1_Click(object sender, EventArgs e) { string server = "-------"; //your ip address string ftpPath = "ftp://" + server + "//Files//" +FileUpload1.FileName; string uname = "-----"; string password = "----------"; string filePath = Server.MapPath("~") + "\" + FileUpload1.FileName; try { UploadToFTP(ftpPath,filePath,uname,password); } catch (Exception ex) { //logic here } } 3 y protected void Button1_Click(object sender, EventArgs e) { string server = "-------"; //your ip address string ftpPath = "ftp://" + server + "//Files//" +FileUpload1.FileName; string uname = "-----"; string password = "----------"; string filePath = Server.MapPath("~") + "\" + FileUpload1.FileName; try { UploadToFTP(ftpPath,filePath,uname,password); } catch (Exception ex) { //logic here } } 4 Tienen un comportamiento ligeramente diferente, ambos darán como resultado el hilo llamado para dormir para siempre, y el hilo de llamada que se bloquea para siempre (en su ejemplo).

Solo un aborto grosero puede forzar un hilo bloqueado para salir de un bloque finalmente, y estos solo pueden elevarse por el CLR en sí (ni siquiera puede usar la reflexión para Diddle protected void Button1_Click(object sender, EventArgs e) { string server = "-------"; //your ip address string ftpPath = "ftp://" + server + "//Files//" +FileUpload1.FileName; string uname = "-----"; string password = "----------"; string filePath = Server.MapPath("~") + "\" + FileUpload1.FileName; try { UploadToFTP(ftpPath,filePath,uname,password); } catch (Exception ex) { //logic here } } 525 , ya que hace un CLR interno Llame para obtener el protected void Button1_Click(object sender, EventArgs e) { string server = "-------"; //your ip address string ftpPath = "ftp://" + server + "//Files//" +FileUpload1.FileName; string uname = "-----"; string password = "----------"; string filePath = Server.MapPath("~") + "\" + FileUpload1.FileName; try { UploadToFTP(ftpPath,filePath,uname,password); } catch (Exception ex) { //logic here } } 6 - No hay oportunidad de ser fácilmente malvado allí ...).

El CLR evita que el código de usuario cause que finalmente los bloques se salgan prematuramente para nuestro propio bien, ayuda a prevenir el estado dañado.

para un ejemplo del comportamiento ligeramente diferente con protected void Button1_Click(object sender, EventArgs e) { string server = "-------"; //your ip address string ftpPath = "ftp://" + server + "//Files//" +FileUpload1.FileName; string uname = "-----"; string password = "----------"; string filePath = Server.MapPath("~") + "\" + FileUpload1.FileName; try { UploadToFTP(ftpPath,filePath,uname,password); } catch (Exception ex) { //logic here } } 7 :

  protected void Button1_Click(object sender, EventArgs e) {      string server = "-------"; //your ip address     string ftpPath = "ftp://" + server + "//Files//" +FileUpload1.FileName;     string uname = "-----";     string password = "----------";     string filePath = Server.MapPath("~") + "\" + FileUpload1.FileName;      try      {          UploadToFTP(ftpPath,filePath,uname,password);         }      catch (Exception ex)      {         //logic here       }         } 8  

 

Aborting and interrupting threads should be avoided if possible as this can corrupt the state of a running program. For example, imagine you aborted a thread that was holding locks open to resources, these locks would never be released.

Instead consider using a signalling mechanism so that threads can co-operate with each other and so handle blocking and unblocking gracefully, e.g:

    private readonly AutoResetEvent ProcessEvent = new AutoResetEvent(false);     private readonly AutoResetEvent WakeEvent = new AutoResetEvent(false);      public void Do()     {         Thread th1 = new Thread(ProcessSomething);         th1.IsBackground = false;         th1.Start();          ProcessEvent.WaitOne();          Console.WriteLine("Processing started...");          Thread th2 = new Thread(() => WakeEvent.Set());         th2.Start();          th1.Join();         Console.WriteLine("Joined");     }      private void ProcessSomething()     {         try         {             Console.WriteLine("Processing...");             ProcessEvent.Set();         }         finally         {             WakeEvent.WaitOne();             Console.WriteLine("Woken up...");         }     } 

Update

Quite an interesting low-level issue. Although Abort() is documented, Interrupt() is much less so.

The short answer to your question is no, you cannot wake a thread in a finally block by calling Abort or Interrupt on it.

Not being able to abort or interrupt threads in finally blocks is by design, simply so that finally blocks have a chance to run as you would expect. If you could abort and interrupt threads in finally blocks this could have unintended consequences for cleanup routines, and so leave the application in a corrupted state - not good.

A slight nuance with thread interrupting, is that an interrupt may have been issued against the thread any time before it entered the finally block, but whilst it was not in a SleepWaitJoin state (i.e. not blocked). In this instance if there was a blocking call in the finally block it would immediately throw a ThreadInterruptedException and crash out of the finally block. Finally block protection prevents this.

As well as protection in finally blocks, this extends to try blocks and also CERs (Constrained Execution Region) which can be configured in user code to prevent a range of exceptions being thrown until after a region is executed - very useful for critical blocks of code which must be completed and delay aborts.

The exception (no pun intended) to this are what are called Rude Aborts. These are ThreadAbortExceptions raised by the CLR hosting environment itself. These can cause finally and catch blocks to be exited, but not CERs. For example, the CLR may raise Rude Aborts in response to threads which it has judged to be taking too long to do their work\exit e.g. when trying to unload an AppDomain or executing code within the SQL Server CLR. In your particular example, when your application shuts down and the AppDomain unloads, the CLR would issue a Rude Abort on the sleeping thread as there would be an AppDomain unload timeout.

Aborting and interrupting in finally blocks is not going to happen in user code, but there is slightly different behavior between the two cases.

Abort

When calling Abort on a thread in a finally block, the calling thread is blocked. This is documented:

The thread that calls Abort might block if the thread that is being aborted is in a protected region of code, such as a catch block, finally block, or constrained execution region.

In the abort case if the sleep was not infinite:

  1. The calling thread will issue an Abort but block here until the finally block is exited i.e. it stops here and does not immediately proceed to the Join statement.
  2. The callee thread has its state set to AbortRequested.
  3. The callee continues sleeping.
  4. When the callee wakes up, as it has a state of AbortRequested it will continue executing the finally block code and then "evaporate" i.e. exit.
  5. When the aborted thread leaves the finally block: no exception is raised, no code after the finally block is executed, and the thread's state is Aborted.
  6. The calling thread is unblocked, continues to the Join statement and immediately passes as the called thread has exited.

So given your example with an infinite sleep, the calling thread will block forever at step 1.

Interrupt

In the interrupt case if the sleep was not infinite:

Not so well documented...

  1. The calling thread will issue an Interrupt and continue executing.
  2. The calling thread will block on the Join statement.
  3. The callee thread has its state set to raise an exception on the next blocking call, but crucially as it is in a finally block it is not unblocked i.e. woken.
  4. The callee continues sleeping.
  5. When the callee wakes up, it will continue executing the finally block.
  6. When the interrupted thread leaves the finally block it will throw a ThreadInterruptedException on its next blocking call (see code example below).
  7. The calling thread "joins" and continues as the called thread has exited, however, the unhandled ThreadInterruptedException in step 6 has now flattened the process...

So again given your example with an infinite sleep, the calling thread will block forever, but at step 2.

Summary

So although Abort and Interrupt have slightly different behavior, they will both result in the called thread sleeping forever, and the calling thread blocking forever (in your example).

Only a Rude Abort can force a blocked thread to exit a finally block, and these can only be raised by the CLR itself (you cannot even use reflection to diddle ThreadAbortException.ExceptionState as it makes an internal CLR call to get the AbortReason - no opportunity to be easily evil there...).

The CLR prevents user code from causing finally blocks to be prematurely exited for our own good - it helps to prevent corrupted state.

For an example of the slightly different behavior with Interrupt:

internal class ThreadInterruptFinally {     public static void Do()     {         Thread t = new Thread(ProcessSomething) { IsBackground = false };         t.Start();         Thread.Sleep(500);         t.Interrupt();         t.Join();     }      private static void ProcessSomething()     {         try         {             Console.WriteLine("processing");         }         finally         {             Thread.Sleep(2 * 1000);         }          Console.WriteLine("Exited finally...");          Thread.Sleep(0); //<-- ThreadInterruptedException     } }    
 
 
4
 
vote

El bloqueo completo de un bloque es mantener algo que no se verá afectado por una interrupción o abortar y se ejecutará a la finalización normal, sin importar qué. Permitir que un bloque //Call A FileUpload Method of FTP Request Object reqObj.Method = WebRequestMethods.Ftp.UploadFile; //If you want to access Resourse Protected,give UserName and PWD reqObj.Credentials = new NetworkCredential(strUserName, strPassword); // Copy the contents of the file to the byte array. byte[] fileContents = File.ReadAllBytes(strLocalFilePath); reqObj.ContentLength = fileContents.Length; //Upload File to FTPServer Stream requestStream = reqObj.GetRequestStream(); // Stream requestStream = response.GetResponseStream(); requestStream.Write(fileContents, 0, fileContents.Length); requestStream.Close(); FtpWebResponse response = (FtpWebResponse)reqObj.GetResponse(); response.Close(); Label1.Text = "File Transfered Completed" + response.StatusDescription; } catch (Exception Ex) { throw Ex; } return true; } ` 0303030630 se aburde o interrumpido. Lamentablemente, como se señaló, //Call A FileUpload Method of FTP Request Object reqObj.Method = WebRequestMethods.Ftp.UploadFile; //If you want to access Resourse Protected,give UserName and PWD reqObj.Credentials = new NetworkCredential(strUserName, strPassword); // Copy the contents of the file to the byte array. byte[] fileContents = File.ReadAllBytes(strLocalFilePath); reqObj.ContentLength = fileContents.Length; //Upload File to FTPServer Stream requestStream = reqObj.GetRequestStream(); // Stream requestStream = response.GetResponseStream(); requestStream.Write(fileContents, 0, fileContents.Length); requestStream.Close(); FtpWebResponse response = (FtpWebResponse)reqObj.GetResponse(); response.Close(); Label1.Text = "File Transfered Completed" + response.StatusDescription; } catch (Exception Ex) { throw Ex; } return true; } ` 1 bloques se pueden abortar o interrumpir debido a varias condiciones de carrera. Esta es la razón por la que verá a muchas personas que le aconsejan que no interrumpan o abortan los hilos.

En su lugar, use el diseño cooperativo. Si se supone que se debe interrumpir un hilo, en lugar de llamar //Call A FileUpload Method of FTP Request Object reqObj.Method = WebRequestMethods.Ftp.UploadFile; //If you want to access Resourse Protected,give UserName and PWD reqObj.Credentials = new NetworkCredential(strUserName, strPassword); // Copy the contents of the file to the byte array. byte[] fileContents = File.ReadAllBytes(strLocalFilePath); reqObj.ContentLength = fileContents.Length; //Upload File to FTPServer Stream requestStream = reqObj.GetRequestStream(); // Stream requestStream = response.GetResponseStream(); requestStream.Write(fileContents, 0, fileContents.Length); requestStream.Close(); FtpWebResponse response = (FtpWebResponse)reqObj.GetResponse(); response.Close(); Label1.Text = "File Transfered Completed" + response.StatusDescription; } catch (Exception Ex) { throw Ex; } return true; } ` 2 , use una espera cronometrada. En lugar de llamar //Call A FileUpload Method of FTP Request Object reqObj.Method = WebRequestMethods.Ftp.UploadFile; //If you want to access Resourse Protected,give UserName and PWD reqObj.Credentials = new NetworkCredential(strUserName, strPassword); // Copy the contents of the file to the byte array. byte[] fileContents = File.ReadAllBytes(strLocalFilePath); reqObj.ContentLength = fileContents.Length; //Upload File to FTPServer Stream requestStream = reqObj.GetRequestStream(); // Stream requestStream = response.GetResponseStream(); requestStream.Write(fileContents, 0, fileContents.Length); requestStream.Close(); FtpWebResponse response = (FtpWebResponse)reqObj.GetResponse(); response.Close(); Label1.Text = "File Transfered Completed" + response.StatusDescription; } catch (Exception Ex) { throw Ex; } return true; } ` 3 señal lo que espera el hilo.

 

The whole point of a finally block is to hold something that will not be affected by an interrupt or abort and will run to normal completion no matter what. Permitting a finally block to be aborted or interrupted would pretty much defeat the point. Sadly, as you noted, finally blocks can be aborted or interrupted due to various race conditions. This is why you will see many people advising you not to interrupt or abort threads.

Instead, use cooperative design. If a thread is supposed to be interrupted, instead of calling Sleep, use a timed wait. Instead of calling Interrupt signal the thing the thread waits for.

 
 

Relacionados problema

1  ¿Cuál es la forma correcta de interrumpir un hilo de cliente mientras llama a un método EJB?  ( What is the proper way to interrupt a client thread while its calling an ejb me ) 
Tengo un cliente Java que está administrando sus llamadas de servidor en nuevos hilos para evitar que la GUI se congele. Incluso si se evita esto en muchos ...

3  Java InterruptedException: estoy confundido en cuanto a lo que significa que se interrumpa un hilo o por qué sería  ( Java interruptedexception im confused as to what it even means for a thread t ) 
Sigo obteniendo esta excepción dentro de un bloque sincronizado, en el que llamo espere en el mismo objeto que estoy sincronizado. ¿Qué significa que para un ...

32  En qué casos realiza el futuro. () Lanza Ejecución Ejecución o InterruptivoException  ( In what cases does future get throw executionexception or interruptedexception ) 
MI SNIPPET DE CÓDIGO: ExecutorService executor = Executors.newSingleThreadExecutor(); try { Task t = new Task(response,inputToPass,pTypes,unit.getInsta...

1  ¿Por qué se lanza la percepción de la excepción solo de los métodos de bloqueo como el sueño () y esperan ()?  ( Why is interruptedexception thrown only from blocking methods like sleep and w ) 
Si escribo un código a continuación, no podemos interrumpir ni terminar el hilo. Además, no arrojará interrupción de la excepción. Thread loop = new Thread...

8  ¿En qué condiciones bloquearán la excepción interrumpida?  ( Under what conditions will blockingqueue take throw interrupted exception ) 
Supongamos que tengo un hilo que consume elementos producidos por otro hilo. Su método de ejecución es el siguiente, con la injunta que es un bloqueo boole...

26  Ocasionalmente interrupción de la excepción al abandonar una aplicación oscilante  ( Occasional interruptedexception when quitting a swing application ) 
Recientemente he actualizado mi equipo a uno más potente, con un procesador de cuatro núcleos hyperthreading (i7), por lo tanto mucha concurrencia de bienes d...

4  Interrumpiendo una instrucción de montaje mientras está operando  ( Interrupting an assembly instruction while it is operating ) 
Cuando se produce una interrupción a la CPU, se maneja al ahorrar la ubicación de la dirección actual, saltando hacia el controlador si se reconoce. De lo con...

2  Cierre con gracia a una aplicación Java OpenGL (JOGL)  ( Gracefully shutting down a java opengl jogl app ) 
Tengo una solicitud con un componente JOGL. Cuando se apaga usando System.exit (0), con frecuencia obtiene la excepción: java.lang.InterruptedException at ...

11  ¿Por qué Linux Kernel usa la puerta de trampa para manejar la excepción Divide_Error?  ( Why linux kernel use trap gate to handle divide error exception ) 
En el kernel 2.6.11.5, Divide Cero Exception Handler se configura como: server_id | job_id 1 1 1 2 3 De acuerdo con "Entender ...

2  ¿Cómo manejar Java InterruptException sin interrupciones de la lógica de negocios?  ( How to handle java interruptedexception without business logic break ) 
En primer lugar, leí otra pregunta sobre este artículo y sepa cómo usar <li class="controls__item" v-if="options[0].save == 'show'"> <button class="btn" ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos