Results 1 to 7 of 7

Thread: [RESOLVED] Aborting multiple threaded classes via token cancellation

  1. #1

    Thread Starter
    Member
    Join Date
    Mar 2022
    Posts
    39

    Resolved [RESOLVED] Aborting multiple threaded classes via token cancellation

    It works out that in a large WinForms app that I have, all of the threaded classes, which do a lot of math work, need to be thread as Apartment, or there are significant delegate-related exceptions with the UI (obviously). Many of the classes are started simulataneously to do math work. Recently, I started using coordinated cancellations using a token source.

    The code below is simply for a work class, which is instantiated as:

    Code:
    Dim work As New MathClass()
    The code for each class looks like the following. There is a token source created at the class level, and is passed to the method via the parameter array as object(). The first question is, if I sent cts.token as one of the object arrays elements, will the interpreter (kernel) know that it's a token that can be used for cancellation anywhere in the class? When I want to stop all running classes, I simply click a button on the UI which sets the global AbortAllThreads=1, and then the large iteration loop in the class's method will see that, and then cancel the token. However, I am not sure if i first need to cancel the token only if AbortAllThreads=1 (i.e., cts.token.cancel), and then follow that if statement with a an if statement that listens for IsCancellationRequested? That is, in my case I first have to set cts.token.cancel, and thenn in another if statement test for Is CancellationRequested, and then exit the method.

    Last, based on my code, can I just skip token use, and exit the method, and also use Dispose. While reading the coordinated cancellation pages at MS, most of the language states that during cancelation you really "just need to exit the method." Thus, I believe, for my code, if I trap out the AbortAllThreads, and just exit the method, then GC will start. But would the thread be ended?

    Code:
    Public AbortAllThreads as Byte = 0
    
    Public Class TestClass
        Implements IDisposable
        Public cts As CancellationTokenSource = New CancellationTokenSource
        Dim param_obj() As Object
     
        Sub New()
            ReDim param_obj(2)
            param_obj(0) = param1
            param_obj(1) = param2
            param_obj(2) = cts   'Does this need to be cts.token?
    
            Dim t = New Thread(AddressOf MyMethod)
            t.IsBackground = True
            t.SetApartmentState(ApartmentState.STA)
            t.Start(param_obj)
    
        End Sub
    
        Sub MyMethod(param_obj)
    
            param1 = param_obj(0)
            param2 = param_obj(1)
            cts = param_obj(2)
    
            For i = 1 To NumIters
               'Do all the work for this iteration
               If AbortAllThreads = 1 Then
                       cts.source.Cancel() '.Token.IsCancellationRequested = True Then
                       cts.Dispose
                       Me.Dispose()   'Don't know if this is needed, or GC is automatic
                       Exit Sub
               End If
            Next i
    
        End Sub
    
        Public Overloads Sub Dispose() Implements IDisposable.Dispose
            'Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
    
    End Class
    Last edited by pel11; Mar 16th, 2022 at 09:28 AM. Reason: resolved

  2. #2
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,547

    Re: Aborting multiple threaded classes via token cancellation

    Why are you declaring AbortAllThreads as a byte? Doesn't using a boolean make more sense?

  3. #3
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    37,551

    Re: Aborting multiple threaded classes via token cancellation

    You may not need that dispose at all. I realize that's just an example, but Dispose is there to allow you to clean up anything that needs to be cleaned up, and you don't appear to have anything to clean up. The GC isn't going to do anything unless it has to. As long as no code holds a reference to the class, then the class will just sit there in memory. If memory gets short enough for the GC to run, then it will see that nothing holds a reference to that object and it will be destroyed and the memory reclaimed. That only happens if it is necessary to reclaim the memory, though. Otherwise, an object that nobody references will just be a bit of wasted memory, since it is more efficient to waste a bit of memory than to reclaim it.
    My usual boring signature: Nothing

  4. #4

    Thread Starter
    Member
    Join Date
    Mar 2022
    Posts
    39

    Re: Aborting multiple threaded classes via token cancellation

    @Shaggy Hiker - thanks but do I need to pass cts or cts.token as a parameter? Also, don't I first need to set cts.token cancel if AbortAllThreads=1, and then use another if-statement after this logical to find out if cts.IsCancellationRequested = True, and then exit the method?

  5. #5
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    24,896

    Re: Aborting multiple threaded classes via token cancellation

    Here's a simplified example...

    Code:
    Imports System
    Imports System.Threading
    Public Class Token
        Public Shared Sub Main()
             Dim cancelSource = New CancellationTokenSource()
    	 Call (New Thread(Sub()
    	     Try
    	         Worker1(cancelSource.Token) 
    	     Catch e1 As OperationCanceledException
    		 Console.WriteLine("Worker1 Cancelled!")
    	     End Try
    	  End Sub)).Start()
             Call (New Thread(Sub()
    	     Try
    	         Worker2(cancelSource.Token)
    	     Catch e1 As OperationCanceledException
    		 Console.WriteLine("Worker2 Cancelled!")
    	     End Try
    	  End Sub)).Start()
    
    	  Thread.Sleep(1000)
    	  cancelSource.Cancel() ' Safely cancel workers.
    	  Console.ReadLine()
        End Sub
        
        Private Shared Sub Worker1(ByVal cancelToken As CancellationToken)
    	  Do
    		Console.Write("Worker1")
    		cancelToken.ThrowIfCancellationRequested()
    	  Loop
        End Sub
        Private Shared Sub Worker2(ByVal cancelToken As CancellationToken)
    	  Do
    		Console.Write("Worker2")
    		cancelToken.ThrowIfCancellationRequested()
    	  Loop
        End Sub
    End Class
    Last edited by .paul.; Mar 14th, 2022 at 11:44 PM.

  6. #6
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    24,896

    Re: Aborting multiple threaded classes via token cancellation

    Here's a more complex example, which should be sufficiently similar to yours...

    Code:
    Imports System
    Imports System.Threading
    Public Class Token
        Public Shared Sub Main()
            Dim cancelSource As New CancellationTokenSource()
            Dim t1 As New Thread(Sub()
                                     Try
                                         Worker1(cancelSource, cancelSource.Token, 1, 2)
                                     Catch e1 As OperationCanceledException
                                         Console.WriteLine("Worker1 Cancelled!")
                                     End Try
                                 End Sub) With {.IsBackground = True}
            t1.SetApartmentState(ApartmentState.STA)
            t1.Start()
            Dim t2 As New Thread(Sub()
                                     Try
                                         Worker2(cancelSource, cancelSource.Token, 3, 4)
                                     Catch e1 As OperationCanceledException
                                         Console.WriteLine("Worker2 Cancelled!")
                                     End Try
                                 End Sub) With {.IsBackground = True}
            t2.SetApartmentState(ApartmentState.STA)
            t2.Start()
    
            Thread.Sleep(100000) ' This is just here to keep the console open long enough to run the test threads
            'cancelSource.Cancel() ' Not used here. Safely cancel workers from your UI thread.
            Console.ReadLine()
        End Sub
    
        Private Shared Sub Worker1(ByVal source As CancellationTokenSource, ByVal cancelToken As CancellationToken, p1 As Integer, p2 As Integer)
            Dim counter As Integer = 1
            Do
                Console.WriteLine("Worker1")
                If counter + p2 * 50 > 10000 Then source.Cancel() ' Safely cancel workers from this thread after your calculations have finished.
                cancelToken.ThrowIfCancellationRequested()
                counter += p1
            Loop
        End Sub
        Private Shared Sub Worker2(ByVal source As CancellationTokenSource, ByVal cancelToken As CancellationToken, p1 As Integer, p2 As Integer)
            Dim counter As Integer = 1
            Do
                Console.WriteLine("Worker2")
                If counter + p2 * 50 > 10000 Then source.Cancel() ' Safely cancel workers from this thread after your calculations have finished.
                cancelToken.ThrowIfCancellationRequested()
                counter += p1
            Loop
        End Sub
    End Class
    Last edited by .paul.; Mar 15th, 2022 at 03:34 AM.

  7. #7

    Thread Starter
    Member
    Join Date
    Mar 2022
    Posts
    39

    Re: Aborting multiple threaded classes via token cancellation

    Thanks @Paul, these work great!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width