Non-nil thread gives NilObjectException

  1. 5 months ago

    Beatrix W

    Dec 13 Pre-Release Testers Europe (Germany)

    I'm trying to download some images from the internet. When there is an error the user is asked if he wants to continue or pause downloading. For a long time I have used the code below to show a dialog:

    theMessage = hasMessage
    Button = hasButton
    
    dim currentThread as Thread = App.CurrentThread
    if currentThread = nil then
      HandleAction(Nil)
      return
    end if
    
    'create the timer
    me.ShowDialog = new DelegatingTimer
    me.ShowDialog.Mode = 1
    me.ShowDialog.Period = 100
    me.ShowDialog.Action = AddressOf me.HandleAction
    
    theThread = currentThread
    theThread.suspend

    where the dialog is shown in HandleAction. However, today I'm totally astonished to get a NilObjectException in the last line. The debugger shows me that theThread is not Nil. The assignment is only made when currentThread isn't Nil. So how can there be a NOE?

    The download is an additional feature of a parser which can continue without downloading. So if there are network problem I'd like to ask if the use want to continue or not.

    Does anyone have an idea what might be going on here?

    Xojo 2018r3, High Sierra.

  2. Beatrix W

    Dec 14 Pre-Release Testers Europe (Germany)

    Any ideas? The location of the crash seems accidental. If I take out the error I get the NOEs all over the place. The NOEs are related to the way I do an array of sockets:

    'make some sockets
    for currentSocket as Integer = 0 to Min(UBound(theSecureSocket), UBound(theLinks))
      theSecureSocket(currentSocket) = new HTTPSecureSocket
      'get the events
      AddHandler theSecureSocket(currentSocket).PageReceived, WeakAddressOf PageReceived_Handler
      AddHandler theSecureSocket(currentSocket).Error, WeakAddressOf Error_Handler
    next
    
    'start downloading
    for currentSocket as Integer = 0 to Min(UBound(theSecureSocket), UBound(theLinks))
      dim nextLink as String = theLinks.Pop
      if Left(nextLink, 5) = "https" then theSecureSocket(currentSocket).Secure = True
      theSecureSocket(currentSocket).Get(nextLink)
    Next
    
    'check if we are finished
    dim Timeout as integer = Ticks + 60 * 10
    while not isFinished and Ticks < Timeout
      if Globals.StopArchiving then Return
      app.SleepCurrentThread(10)
    wend

    Error_Handler terminates processing, PageReceived_Handler continues processing:

    'download the next link
    dim nextLink as String = theLinks.Pop
    if Left(nextLink, 5) = "https" then Sender.Secure = True
    Sender.Get(nextLink)

    Is this something stupid?

  3. To me, it looks like the App object which can become nil on quitting before everything has been executed.

    I would recommend to check App and App.currentThread against nil everytime you access them

  4. Beatrix W

    Dec 14 Pre-Release Testers Europe (Germany)

    The app isn't quitting. After adding a check on App.currentThread I STILL get an NOE. The NOEs are related to my socket array. I must be doing something stupid there.

  5. Derk J

    Dec 14 Pre-Release Testers, Xojo Pro

    CurrentThread returns Nil if it’s the main thread

  6. Beatrix W

    Dec 14 Pre-Release Testers Europe (Germany)

    Ahem... have a look at the start of my code:

    dim currentThread as Thread = App.CurrentThread
    if currentThread = nil then
      HandleAction(Nil)
      return
    end if

    Again: it's my sockets that make the mess. I just don't understand why and how to fix the problem.

  7. Are we sure that AddHandler (and related methods) are truly compatible with Threads?

    Maybe instead on relying on AddHandler you could subclass your socket class so it executes itself the code of PageReceived_Handler and Error_Handler. At least just to see if you still get a NOE

  8. Beatrix W

    Dec 14 Pre-Release Testers Europe (Germany)

    @Stephane Mons: good idea. I'll try the subclassing tomorrow.

  9. Tim P

    Dec 14 Pre-Release Testers Rochester, NY

    Try switching to a Namespaced Framework socket and using 2018r2 (I'm not seeing any good news about URLConnection) while testing that theory.

    I have a wrapper class that does some Text and Xojo.Core.Memoryblock to String conversion so that the returned contents in PageReceived are a String. It's not super complete so I don't share it openly, but I know you'll fix whatever you need if you need to, so if you'd like it just drop me a PM or email. :)

  10. Ulrich B

    Dec 16 Pre-Release Testers, Xojo Pro Europe (Germany, Berlin) · xo...

    Are you keeping the threads somewhere as a reference or could there be a chance that the thread finishes between you checking it for being nil and then handling it?
    (Yes, I see it as a rather tiny chance, but it would be the only explanation for me why this could be happening without suspecting a Xojo bug: The thread, being a self-referencing object, finishes, gets out of scope and so becomes nil.)

  11. Beatrix W

    Dec 16 Pre-Release Testers Europe (Germany)

    Nope. Main thread and one single additional thread. The problem shows only up with the socket array. For one single socket everything is okay - just too slow.

  12. Derk J

    Dec 16 Pre-Release Testers, Xojo Pro
    Edited 5 months ago

    Maybe you get a Nil Thread still cause the context switches back to the mainthread which is nil?

    You request a reference from app.currentthread so you may end up getting it Nil at any point.

    You may want to run trough the debugger with break on exceptions on, the find the reference of ththread and see if it’s nil at that line ending for some unknown reason
    This sounds very impossible i know, but still you give info that sounds impossible so i’d be searching trough the debugger.

  13. Ulrich B

    Dec 16 Pre-Release Testers, Xojo Pro Europe (Germany, Berlin) · xo...

    @Derk J Maybe you get a Nil Thread still cause the context switches back to the mainthread which is nil?

    Good point! @Beatrix, what would happen if you move the suspend call to an else extension of the If clause above?

  14. Tim J

    Dec 16 Pre-Release Testers, Xojo Pro Dehydrating in AZ

    @Derk J Maybe you get a Nil Thread still cause the context switches back to the mainthread which is nil?

    BTDT! I chased a shell that would throw an NOE and it turned out to be exactly that - in some runs, the context switched just prior to my assigning my local thread reference. That ended up assigning my local reference to Nil because App.CurrentThread was the main loop.

  15. Derk J

    Dec 16 Pre-Release Testers, Xojo Pro

    You call App.CurrentThread from the maintrhead and expect it to be another thread, then it can happen if you call App.CurrentThread and it's even expected to be Nil (mainthread).

    you may be better off doing this only within the thread and just keep it running forever or with a flag that may end the thread.

  16. Beatrix W

    Dec 17 Pre-Release Testers Europe (Germany)
    Edited 5 months ago

    It must be something with context switches. However, the error dialog is only supposed to show when the socket has an error and has finished processing.

    Gr... today the error is not reproducible. Which I so totally love.

    Then I did more testing and got a website with HTTP 1.1. Tried to use the newer socket. But on the help page it says:

    Do not attempt to re-use a socket that is still in use (e.g. directly from the PageReceived or FileReceived events). One solution is to use a separate Timer that checks if the socket is available before attempting to use it again, but for bests results you will probably want to create a new socket.

    Which is about as clear as mud.

  17. Tim P

    Dec 17 Pre-Release Testers Rochester, NY

    @Beatrix that one means in the PageReceived event do not re-use the socket itself. Something happens and it's bugged for the second request. Creating a new socket object is safe to do. I usually build a queue system and add sockets to an array, removing them after they have completed.

or Sign Up to reply!