Announcement

Collapse
No announcement yet.

Thread Status

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Scott Turchin
    replied
    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
    '==========================================================================================

    Leave a comment:


  • John Petty
    replied
    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

    Leave a comment:


  • Cliff Nichols
    replied
    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?

    Leave a comment:


  • Michael Mattias
    replied
    > 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

    Leave a comment:


  • Scott Turchin
    replied
    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.

    Leave a comment:


  • Michael Mattias
    replied
    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

    Leave a comment:


  • Scott Turchin
    replied
    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.

    Leave a comment:


  • Scott Turchin
    replied
    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..

    Leave a comment:


  • Michael Mattias
    replied
    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.

    Leave a comment:


  • Dale Yarker
    replied
    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.

    Leave a comment:


  • Scott Turchin
    started a topic Thread Status

    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.
Working...
X