Threads Don't Abort Easily

joe_pool_is

Contributor
Joined
Jan 18, 2004
Messages
507
Location
Longview, TX [USA]
We've got a thread in our application that does work.

If we need to make changes on the fly, we stop the thread by calling it's Abort() call, change settings to the parameters, and restart the thread.

The problem is, whenever we call Abort() on the thread, sometimes it just doesn't abort! I found this out when I put a "While (MyThread.ThreadState <> ThreadState.Stopped)" Loop into my routine, and it never returned.

How do I get the thread to stop, and really stop, so that I can make changes to the settings it uses and then restart the thread?
 
Does this help?
Visual Basic:
  Private m_thTCP As Thread
  Private m_listener As TcpListener
  Public Sub New()
    InitializeComponent() ' This call is required by the Windows Form Designer.
    m_thTCP = New Thread(AddressOf TCPServer)
    ThreadStart()
  End Sub
  Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    ThreadStop()
  End Sub
  Private Sub Restart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RestartButton.Click
    ThreadRestart()
  End Sub
  Private Sub ThreadStop() ' Stopping TCP Listener Service
    Try
      If (m_thTCP.ThreadState <> ThreadState.Stopped) Then
        Dim i As Int16 = 0
        m_listener.Stop()
        Application.DoEvents()
        Thread.Sleep(200)
        While ((i < 100) And (m_thTCP.ThreadState <> ThreadState.Stopped)) ' gives thread 5 secs to stop!
          m_thTCP.Abort()
          Application.DoEvents()
          Thread.Sleep(50)
          i += 1
        End While
      End If
    Catch ex As Exception
      MsgBox(ex.Message)
    Finally
      Console.WriteLine("ThreadState is {0}", m_thTCP.ThreadState.ToString())
      m_thTCP = Nothing
    End Try
  End Sub
  Public Sub ThreadRestart() ' Restarting TCP Listener Service
    Try
      ThreadStop()
      m_thTCP = New Thread(AddressOf TCPServer)
      ThreadStart()
    Catch ex As Exception
      MsgBox(ex.Message)
    End Try
  End Sub
  Private Sub ThreadStart()
    Try
      m_thTCP.Start()
    Catch ex As Exception
      MsgBox(ex.Message)
    End Try
  End Sub
  Private Sub TCPServer()
    Try ' Starting TCP Listener from thread
      m_listener = New TcpListener(IPAddress.Any, m_port)
      m_listener.Start()
      While True
        Dim client As TcpClient = m_listener.AcceptTcpClient() ' Waits until data is available on the network
        Dim stream As NetworkStream = client.GetStream()
        Dim bytes(client.ReceiveBufferSize) As Byte
        stream.Read(bytes, 0, CInt(client.ReceiveBufferSize))
        Dim data As String = Encoding.ASCII.GetString(bytes)
        data = data.TrimEnd(data.Substring(data.Length - 1))
        If (data.Substring(3) <> String.Empty) Then
          Dim item As String = data.Substring(3)
          If (item <> "") Then
            Console.WriteLine("Data Read: {0}", item)
          End If
        End If
        stream.Close()
        client.Close()
      End While
    Catch ex2 As SocketException
      Console.WriteLine("SocketException: {0}", ex2)
    Catch ex1 As ThreadAbortException ' dismiss this one
      Exit Sub
    Catch ex As Exception
      MsgBox(ex.Message)
    Finally
      Try
        m_listener.Stop()
      Catch ex As Exception ' Throws Exception if it never was opened
      End Try
    End Try
  End Sub
 
Last edited:
This line:

Dim client As TcpClient = m_listener.AcceptTcpClient() ' Waits until data is available on the network

is a blocking call. You even put a comment there to signify that it waits.

An ugly way to cancel the blocking call would be to call m_listener.Close() in the ThreadStop() method.

But, my recommendation would be to forgo threading in this case and use asynchronous callbacks, which are internally managed threads anyway. Use the BeginAcceptTcpClient method of TcpClient.

Another tip, when writing debug information, include the namspace System.Diagnostics and use the Debug class.
 
One of the things I like about forums is when they give me ideas I hadn't considered. You gave me 2 new ideas here that I've never used, and I suppose it is about time that I add them to the list of tricks I know.

One was asynchronous callbacks. I had seen BeginAcceptTcpClient and EndAcceptTcpClient methods in the TcpClient class, but couldn't see any reason that I'd want to use them. I'll be looking into this ...second thing!

First thing is the second thing you showed me, which was the System.Diagnostics namespace and the Debug class. I've never used them, so I'll be Googling shortly for an example on how to use it.

Thanks Diesel. I appreciate your time.
 
Back
Top