Thread Status

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts
  • Scott Turchin
    Member
    • Aug 1998
    • 3171

    Thread Status

    Am I to understand the PB Documentation in 8.04 that THREAD STATUS will return if the thread is still running regardless that the thread was closed?

    I'm thinking it's NOT in my best interest to close the thread until I've done a thread status and ensured it's complete. We had that conversation in the internet forum.....

    Found my solution to handling the connection in a separate thread though, and it's far faster...

    Reason I believe this is that my lil mini webserver may get bogged down and take more time in the event say, 200 people connected....There's also preventing a DOS attack on it...

    I open a thread, receive a header, send a header and a page and close....

    But I want to put a bandwidth limitation in of say 250 connections....so if Thread Status returns that a thread still has &H103 status (STill running) then I want to subtract the available threads, going to make that a user definable option starting at say 100....

    Unless anyone has input on limiting connections?

    Code:
    %MAXTHREADS = 100 'Concurrent connections
    %THREADALIVE =  &H103
    
    
    
    
        Case %TCP_ACCEPT
            Select Case Lo(Word, CbLParam)
                Case %FD_ACCEPT 'Create the new thread here
                    Incr tcpCount
                    Control Set Text CbHndl,%IDCONNLABELTL, Format$(tcpCount,"")
                    Control Set Focus CbHndl, %IDLABEL1
                    hTcp = FreeFile
                    Tcp Accept nServer As hTcp
                    Tcp Notify hTcp, Recv Close To CbHndl As %TCP_HTML
                    Function = %TRUE
               End Select
    
        Case %TCP_HTML
            Select Case Lo(Word, CbLParam)
                Case %FD_READ
                    If hTcp <> %INVALID_SOCKET Then
                        'Grab client IP and insert here
                        lHost = RemoteIp(ByVal hTcp)
                    End If
                    hThread(tcpCount) = SendDataThread(ByVal hTcp,lHost)
                    hTcp = %INVALID_SOCKET 'This may be too soon on a slow connection...maybe poll it at 60 seconds?
    
                Case %FD_CLOSE
                    Tcp Close hTcp
                    hTcp = %INVALID_SOCKET
            End Select
    
    
    
        Case %WM_TIMER
            Select Case CbWParam
              Case %IDT_TIMER1
                  g_BBSDown = LoadHtmlPage()
                  g_BBSDownImage = LoadImageFile()
                  sTmp = BBSDown.szMine & " " & BBSDown.szVer & " - " & BBSDown.szCopyrite
                  SendMessage BBSDown.hStatus, %WM_SETTEXT, 0, StrPtr(sTmp)
                  For lLoop = 1 To %MAXTHREADS
                      Thread Status hThread(lLoop) To lResult
                      If lResult = %THREADALIVE Then
                          Decr ThreadsAvailable
                      End If
                  Next
                          
    
    
    
    
    --------------------------------------------------------------------------------------------
    '==========================================================================================
    'THREAD FOR Sending Data
    Function SendDataThread(ByVal hTcp As Long,lHost As String) As Long
    Local hThread   As Long
    Local lResult   As Long
    Thread Create SendDataThreadProc(ByVal hTcp) To hThread
    Thread Close hThread To lResult
    hThread = %FALSE
    End Function
    '==========================================================================================
    Function SendDataThreadProc(ByVal hTcp As Long) As Long
    Local lResult   As Long
    Local lLoop     As Long
    Local lCount    As Long
    Local ErrType   As Long
    Local Header    As String
    Local sBuffer   As String
    Local sPacket   As String
    Local sTmp      As String
    Local lHost     As String
    
    
    lHost = RemoteIp(ByVal hTcp)
    sTmp = TimeStamp() & " Connection established from: " & lHost
    lResult = SendMessage(BBSDown.txtHandle, %LB_ADDSTRING, 0, StrPtr(sTmp))
    lResult = SendMessage(BBSDown.txtHandle, %LVM_GETITEMCOUNT, 0, 0)
    lResult = SendMessage(BBSDown.txtHandle, %LVM_SETITEM, 0, lResult)
    
    
    ' Perform a receive-loop until there is no data left (ie, the end of stream)
    sBuffer = ""
    sPacket = ""
    Do
        Tcp Recv hTcp, 1024, sBuffer
        sPacket = sPacket & sBuffer
        If Len(sPacket) > 4096 Then Exit Do 'Buffer overflow prevention
    '    ErrType = GetLastError()
    Loop Until sBuffer = "" Or IsTrue Eof(hTcp) Or IsTrue Err
    sPacket = Left$(sPacket,Len(sPacket)-2)
    lResult = ParseAndUpdateLogfile(ByVal sPacket,ByVal hTcp) 'Updates window
    ' <-------------Send data and disconnect------------->
    Header = "HTTP/1.1 200" & $CrLf
    Header = Header & "Server: " & BBSDown.szMine & $CrLf
    Header = Header & "Date: " & GetPCTimeandDate() & $CrLf
    Header = Header & "Cache-Control: no-cache" & $CrLf
    Header = Header & "Connection: close" & $CrLf
    
    If IsFalse lResult Then 'html
        Header = Header & "Content-Type: text/html" & $CrLf
        Header = Header & "Content-Length: " & Format$(Len(g_BBSDown)) & $CrLf
        Tcp Send hTcp, Header & $CrLf
        Tcp Send hTcp, g_BBSDown
    Else 'jpg
        Header = Header & "Content-Type: image/jpeg" & $CrLf
        Header = Header & "Content-Length: " & Format$(Len(g_BBSDownImage)) & $CrLf
        Header = Header & "Accept-range: bytes"  & $CrLf 'or something like that.
        Tcp Send hTcp, Header & $CrLf
        Tcp Send hTcp, g_BBSDownImage
    End If
    Tcp Close hTcp
    ' <-------------Send data and disconnect------------->
    'End connection here
    ErrType = GetLastError()
    If ErrType <> %ERROR_SUCCESS Then
    '    Control Get Text CbHndl,%IDTEXT1 To sTmp
        If Not IsFalse Len(sTmp) Then
            sTmp = sTmp & $CrLf & TimeStamp() & " Error: " & Format$(ErrType) & " - " & GetLastErrorDescription(ErrType)' & $CrLf & "Remote IP: " & lHost
        Else
            sTmp = TimeStamp() & " Error: " & Format$(ErrType) & " - " & GetLastErrorDescription(ErrType)' & $CrLf & "Remote IP: " & lHost
        End If
        'Write sTmp
        SendMessage(BBSDown.txtHandle, %LB_ADDSTRING, 0, StrPtr(sTmp))
    End If
    End Function
    '==========================================================================================
    Last edited by Scott Turchin; 17 Oct 2008, 10:03 AM.
    Scott Turchin
    MCSE, MCP+I
    http://www.tngbbs.com
    ----------------------
    True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi
  • Dale Yarker
    Member
    • Mar 2004
    • 5508

    #2
    No, once you do THREAD CLOSE the handle is released, even if the thread is still running. You need the handle to do THREAD STATUS, no handle, no status.

    So yes, don't close till you're done with the handle. From what you describe, that would be after the thread has exited.

    Cheers,
    Last edited by Dale Yarker; 17 Oct 2008, 10:14 AM.
    Dale

    Comment

    • Michael Mattias
      Member
      • Aug 1998
      • 43486

      #3
      Am I to understand the PB Documentation in 8.04 that THREAD STATUS will return if the thread is still running regardless that the thread was closed?

      I'm thinking it's NOT in my best interest to close the thread until I've done a thread status and ensured it's complete. We had that conversation in the internet forum.....
      THREAD STATUS will always return. If it returns a value of &h103 WITH NO ERROR then the thread function is 'still executing'

      However, you should get an 'invalid handle' error if the thread handle used in the THREAD STATUS statement has been closed. (You don't "close a thread" although you may "close a handle to the thread." We had that conversation in the other forum, too.)

      I don't know what PB error is thrown for this particular error condition.

      However....
      Code:
       DO
          THREAD STATUS hThread TO iREt 
       LOOP UNTIL iRet <> &h103
       THREAD CLOSE hThread TO X     ' the "TO " requirement here is IMNSHO silly
      ..is the wimp way to wait for a thread to complete.

      Real Men would use
      Code:
        WaitForSingleObject  hThread, %INIFINTE
        THREAD STATUS  hThread To iRet 
        THREAD CLOSE hThread to X    ' TO X still silly
      MCM
      PS: using the Real Man approach also allows your thread function to return &h103 as a valid return value!
      Last edited by Michael Mattias; 17 Oct 2008, 10:44 AM.
      Michael Mattias
      Tal Systems (retired)
      Port Washington WI USA
      [email protected]
      http://www.talsystems.com

      Comment

      • Scott Turchin
        Member
        • Aug 1998
        • 3171

        #4
        OK I want to use that WAitForSingleObject - I've got it in there but remarked out.
        BUT - if I use that with %INFINITE and that thread hangs or locks up - it'll keep waiting, no?
        I would think using my g_Timeout value or 10000 or 20000 should be sufficient for even the most bogged down computer....


        Now all of that is good- on top of that but another problem exists -

        If I do an array of thread handles to limit the threads- I've noticed I only have ONE hTCP

        Therefore I'm going to need %MAXTHREADS hTcp Handles, ie 100


        Otherwise hTCP = Freefile and it's passed around in the DialogpRoc pump but it's only going to handle ONE connection at a time..

        So the big problem is how to pass on hTcp(value) to FD_READ, FD_CLOSE and keep them synchronized...

        Let me see if I can get the code back in here....brb..
        Scott Turchin
        MCSE, MCP+I
        http://www.tngbbs.com
        ----------------------
        True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

        Comment

        • Scott Turchin
          Member
          • Aug 1998
          • 3171

          #5
          OK WaitForSingleObject works great.

          Now, got any idea how I can synchronized hTCP here?

          FD_READ is NOT going to work simpliy because hTcp(lLoop) is too dynamic, it'll be changed....

          Would be nice to have 100 tcp handles available....

          Code:
              Case %TCP_ACCEPT
                  Select Case Lo(Word, CbLParam)
                      Case %FD_ACCEPT 'Create the new thread here
                          Incr tcpCount
                          Control Set Text CbHndl,%IDCONNLABELTL, Format$(tcpCount,"")
                          Control Set Focus CbHndl, %IDLABEL1
                          For lLoop = 1 To %MAXTHREADS
                              'Make sure we have an available hthread, hTCP will be based on this
                              If IsFalse hThread(lLoop) Then
                                  hTcp(lLoop) = FreeFile
                                  Tcp Accept nServer As hTcp(lLoop)
                                  Tcp Notify hTcp(lLoop), Recv Close To CbHndl As %TCP_HTML
                              End If
                          Next
                          Function = %TRUE
                     End Select
          
              Case %TCP_HTML
                  Select Case Lo(Word, CbLParam)
                      Case %FD_READ
                          If hTcp(lLoop) <> %INVALID_SOCKET Then
                              'Grab client IP and insert here
                              lHost = RemoteIp(ByVal hTcp(lLoop))
                              hThread(lLoop) = SendDataThread(ByVal hTcp(lLoop))
                          End If
          
                      Case %FD_CLOSE
                          Tcp Close hTcp(lLoop)
                          hTcp(lLoop) = %INVALID_SOCKET
                  End Select
          Last edited by Scott Turchin; 17 Oct 2008, 11:01 AM.
          Scott Turchin
          MCSE, MCP+I
          http://www.tngbbs.com
          ----------------------
          True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

          Comment

          • Michael Mattias
            Member
            • Aug 1998
            • 43486

            #6
            Code:
            WinMain
            LOCAL hThread()  AS LONG
            REDIM hThread (some) 
            DO Whenever needed 
              INCR iThread 
              THREAD CREATE TcpFunction (param) to hthread (iThread)
            LOOP
            Wait or something
            
            END Winmain
            
            FUNCTION TcpFunction (param) 
               hTCP = Freefile 
               CreateNotitification window for this thread. 
               wait until no more to do on this handle
               Close hTCP 
               Destroy Notification window
            END FUNCTION
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment

            • Scott Turchin
              Member
              • Aug 1998
              • 3171

              #7
              I tried that notification window thing remember?
              I think the Dialog DoEvents is broken in my version.

              Modeless closed too soon, Modal is still onlyi one TCP connection at a time...I think.......except for that Postmessage api that I haven't used in 15 years....

              OK I would *THINK*, although I'm not sure, but I would imagine hTCP is being passed here as a lo or hiwrd or something somewhere???
              I could recover hTcp as a prameter of FD_READ or FDCLOSE? Or is it not set?
              I Tried the Lo(Word, CBL, CBW, Hi of each, none came out to match....


              Code:
                  Case %TCP_ACCEPT
                      Select Case Lo(Word, CbLParam)
                          Case %FD_ACCEPT 'Create the new thread here  
                                      Tcp Notify hTcp(lLoop), Recv Close To CbHndl As %TCP_HTML  
                      End Select
              
                  Case %TCP_HTML
                      Select Case Lo(Word, CbLParam)
                          Case %FD_READ 
                          Case %FD_CLOSE 
                      End Select
              Last edited by Scott Turchin; 17 Oct 2008, 11:32 AM.
              Scott Turchin
              MCSE, MCP+I
              http://www.tngbbs.com
              ----------------------
              True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

              Comment

              • Michael Mattias
                Member
                • Aug 1998
                • 43486

                #8
                > think the Dialog DoEvents is broken in my version.

                So create your notification window with CreateWindowEx, not DIALOG NEW and use a "real" message loop in the thread function... as demo'd here:
                Progress Bar Dialog for PB/CC programs October 24, 2002
                (Ignore the "PB/CC" in the thread title. This will work in a GUI program exactly the same way).

                Note that each thread which creates a GUI window needs its own message queue.

                That is, you will have one notification window for each current TCP session. If all that Window does is handle TCP notifications, no reason it has to be visible.

                For that matter, there is such a thing as a "message only" window but my SDK is too old to tell me how to do that, I'd have to go to MS online. (At least I think you could use that).

                MCM
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment

                • Cliff Nichols
                  Member
                  • Aug 2006
                  • 3753

                  #9
                  I may have missed it, but if a hang, then wouldn't MCM's "Abort that Worker Thread" (or something like that), come into play here?
                  Engineer's Motto: If it aint broke take it apart and fix it

                  "If at 1st you don't succeed... call it version 1.0"

                  "Half of Programming is coding"....."The other 90% is DEBUGGING"

                  "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                  Comment

                  • John Petty
                    Member
                    • Feb 2000
                    • 1839

                    #10
                    Scott
                    You are confusing me
                    I think the Dialog DoEvents is broken in my version
                    Not really, you just need to put a 1 msec sleep time in it, didn’t you find that on the search I suggested.
                    Modeless closed too soon, Modal is still onlyi one TCP connection at a time
                    Why?
                    Lets say you want to limit to 10 concurrent connections.
                    Create a Global UDT array with 10 members and one of the fields in that array should be an “in use” flag and the address of that UDT array member is then the single and only variable allowed to be passed to a thread
                    Each thread then just creates a modal dialog which of course has a unique handle which should then be stored in the UDT member as well and in it you create a new socket ie hTCP. All the threads will of course share the same Callback code so the first thing that should happen in the callback is to compare CBHNDL to all the stored handles in the Global UDT so you know which one you are working on. PB is threadsafe so it should be creating new locals for each thread that uses the callback, if you don’t feel safe then don’t use any locals in the callback just make provision for them in the UDT. The last thing the callback should do before DIALOG END CBHNDL (which will also ends the thread) is clear the “in use” flag in the UDT.
                    So when you get a new connection you merely scan the UDT array to see if you have a vacant slot, if not sleep, ignore or whatever you think is best.
                    What if a thread hangs? Just store the start time in the UDT member and on each new connection check no thread has been running longer than an allowed period say 2 or 3 minutes, if so close its Dialog and its TCP handle (which you should have also stored in the UDT) and mark the UDT member as not in use. All this small amount of work means you can still do an immediate THREAD CLOSE as you don’t need the handle anymore and no wait for any objects as all the code is non-blocking.
                    Postmessage api that I haven't used in 15 years....
                    POST and SEND are standard PB instructions, no need for API’s. Obviously one of the things you store in each UDT is the handle of the main (and only visible) dialog which gives feedback to the user.
                    Michael
                    You are correct that the simple ending of a sub or function does not end a modeless dialog though I suspect without any proof that ending a thread does or it would create a memory leak. Forgot that only recently (in my terms) had written a TCP server which relied on that feature and did not need a DIALOG DOEVENTS, I know I am getting old. Outside the scope of Scott’s app so wont confuse it with details.
                    I am always happy to admit the limits of my knowledge.
                    John

                    Comment

                    • Scott Turchin
                      Member
                      • Aug 1998
                      • 3171

                      #11
                      Got my home PC back up and going so I can reply now!

                      I like the idea, and while I probably won't go with a dialog box for each connection this is what I do have, individual threads, and I like the global UDT flag idea, as I usually used g_Finished for a specific thread...

                      So I am going to try to incorporate that - which can be set at the beginning of this function and reset after it's complete...

                      Code:
                      '==========================================================================================
                      'THREAD FOR Sending Data
                      Function SendDataThread(ByVal hTcp As Long) As Long
                      Local hThread   As Long
                      Local lResult   As Long
                      Thread Create SendDataThreadProc(ByVal hTcp) To hThread
                      Function = hThread
                      End Function
                      '==========================================================================================
                      Function SendDataThreadProc(ByVal hTcp As Long) As Long
                      Local lResult   As Long
                      Local lLoop     As Long
                      Local lCount    As Long
                      Local ErrType   As Long
                      Local Header    As String
                      Local sBuffer   As String
                      Local sPacket   As String
                      Local sTmp      As String
                      Local lHost     As String
                      
                      Incr BBSDown.tcpCount
                      
                      lHost = RemoteIp(ByVal hTcp)
                      sTmp = TimeStamp() & " Connection established from: " & lHost
                      
                      lResult = SendMessage(BBSDown.txtHandle, %LB_ADDSTRING, 0, StrPtr(sTmp))
                      lResult = SendMessage(BBSDown.lblHandle, %WM_SETTEXT, 0, BBSDown.tcpCount)
                      'lResult = ListView_SetSelection (BYVAL BBSDown.lblHandle, BYVAL BBSDown.tcpCount)
                      ListView_SetItemState BBSDown.lblHandle, BBSDown.tcpCount, &hFFFFFFFF, %LVIS_SELECTED Or %LVIS_FOCUSED
                      
                      
                      
                      
                      'Perform a receive-loop until there is no data left (ie, the end of stream)
                      sBuffer = ""
                      sPacket = ""
                      Do
                          Tcp Recv hTcp, 1024, sBuffer
                          sPacket = sPacket & sBuffer
                          If Len(sPacket) > 4096 Then Exit Do 'Buffer overflow prevention
                      '    ErrType = GetLastError()
                      Loop Until sBuffer = "" Or IsTrue Eof(hTcp) Or IsTrue Err
                      sPacket = Left$(sPacket,Len(sPacket)-2)
                      lResult = ParseAndUpdateLogfile(ByVal sPacket,ByVal hTcp) 'Updates window
                      ' <-------------Send data and disconnect------------->
                      Header = "HTTP/1.1 200" & $CrLf
                      Header = Header & "Server: " & BBSDown.szMine & $CrLf
                      Header = Header & "Date: " & GetPCTimeandDate() & $CrLf
                      Header = Header & "Cache-Control: no-cache" & $CrLf
                      Header = Header & "Connection: close" & $CrLf
                      
                      If IsFalse lResult Then 'html
                          Header = Header & "Content-Type: text/html" & $CrLf
                          Header = Header & "Content-Length: " & Format$(Len(g_BBSDown)) & $CrLf
                          Tcp Send hTcp, Header & $CrLf
                          Tcp Send hTcp, g_BBSDown
                      Else 'jpg
                          Header = Header & "Content-Type: image/jpeg" & $CrLf
                          Header = Header & "Content-Length: " & Format$(Len(g_BBSDownImage)) & $CrLf
                          Header = Header & "Accept-range: bytes"  & $CrLf 'or something like that.
                          Tcp Send hTcp, Header & $CrLf
                          Tcp Send hTcp, g_BBSDownImage
                      End If
                      Tcp Close hTcp
                      ' <-------------Send data and disconnect------------->
                      'End connection here
                      ErrType = GetLastError()
                      If ErrType <> %ERROR_SUCCESS Then
                          sTmp = TimeStamp() & " Error: " & Format$(ErrType) & " - " & GetLastErrorDescription(ErrType) & " - Remote IP: " & lHost
                          lResult = SendMessage(BBSDown.txtHandle, %LB_ADDSTRING, 0, StrPtr(sTmp))
                      End If
                      End Function
                      '==========================================================================================
                      Scott Turchin
                      MCSE, MCP+I
                      http://www.tngbbs.com
                      ----------------------
                      True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

                      Comment

                      Working...
                      X