It is currently Sun Jun 24, 2018 1:50 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Threads influencing eachother?
PostPosted: Wed Jun 13, 2018 2:07 pm 
Offline
User
User

Joined: Fri Jul 14, 2006 10:27 pm
Posts: 20
Hi,

I'm trying to build a program with two threads. One thread acts as a simpel webserver (with databaseaccess, et cetera), the other thread acts as a telnet server with only one goal: As soon as a client connect, give some data (not from a database, just a text) and disconnect. Apart from eachother, the threads are working great. However, as soon as I let these threads run simultaniously, everything seems mixed up: If I connect to the telnet server, I sometimes get no response, a good response, or a response containing data from the other thread. If I access the webserver, I get an error, or sometimes the message which should be given by the telnetserver.

This is the calling code:
Code:
  Structure WebServer
    port.l
  EndStructure
 
  *Parameters.Webserver = AllocateMemory(SizeOf(WebServer))
  *Parameters\Port.l=WebServerPort
  WebServerThread=CreateThread(@Webserver(),*Parameters)
 
  TelnetServerThread=CreateThread(@pingpong(),*telnetserverport)




PingPong thread:

Code:
Procedure pingpong(*telnetserverport)
 
  If InitNetwork()=0
    ProcedureReturn
  EndIf
 
;  *ReceiveTelnetBuffer=AllocateMemory(1000)
  If CreateNetworkServer(#PB_Any,*telnetserverport,#PB_Network_TCP|#PB_Network_IPv4)
    Repeat
      telnetsEvent=NetworkServerEvent()
      If telnetsEvent
        telnetClientID=EventClient()
        Select telnetsEvent
          Case 1
            Debug "Client "+Str(telnetclientID)+" connected"
            ; client connected
            SendNetworkString(telnetclientID,"pong"+#CRLF$)
            CloseNetworkConnection(telnetclientID)
           
          Case 4
            Debug "Client "+Str(telnetclientID)+" disconnected"
            ; client disconnected
;          Default
;            Debug "Client request"
;            RequestLength = ReceiveNetworkData(ClientID, *ReceiveTelnetBuffer, 2000)
;            ClientRequest.s= PeekS(*ReceiveTelnetBuffer,-1,#PB_UTF8)
;            Debug "Received: "+ClientRequest.s
;            SendNetworkString(ClientID, "pong"+#CRLF$)
        EndSelect
      Else
        Delay(20)
      EndIf
    ForEver
  EndIf
EndProcedure


and the webserver thread:

Code:
Procedure.l BuildRequestHeader(*Buffer, text.s, ContentType$)
  eol$=Chr(13)+Chr(10)
  datalength=Len(text.s)
 
  Length = PokeS(*Buffer, "HTTP/1.1 200 OK"+EOL$, -1, #PB_UTF8)                     : *Buffer+Length
  Length = PokeS(*Buffer, "Date: "+FormatDate("%yyyy %mm %dd %hh:%ii:%ss",Date())+EOL$, -1, #PB_UTF8) : *Buffer+Length
  Length = PokeS(*Buffer, "Server: LVPDFWebServer"+EOL$, -1, #PB_UTF8)      : *Buffer+Length
  Length = PokeS(*Buffer, "Content-Length: "+Str(DataLength)+EOL$, -1, #PB_UTF8)    : *Buffer+Length
  Length = PokeS(*Buffer, "Content-Type: "+ContentType$+EOL$, -1, #PB_UTF8)         : *Buffer+Length
  Length = PokeS(*Buffer, #CRLF$, -1, #PB_UTF8)                                     : *Buffer+Length
  Length = PokeS(*Buffer,text.s+#CRLF$,-1,#PB_UTF8)                                 : *Buffer+Length
 
  ProcedureReturn *Buffer
EndProcedure


Procedure WebServer(*Parameters.WebServer)
 
  Port=*Parameters\Port
 
  ClearStructure(*Parameters, WebServer)
  FreeMemory(*Parameters)
 
 
 
  If InitNetwork() = 0
    debugger("Cannot initialize the network !", 0)
    ProcedureReturn
  EndIf
 
  *receiveBuffer=AllocateMemory(10000)
  If CreateNetworkServer(#PB_Any,port,#PB_Network_TCP|#PB_Network_IPv4)
    Repeat
      sEvent=NetworkServerEvent()
      If sEvent
        ClientID=EventClient()
        Select sEvent
          Case 1
            Debug "Client "+Str(clientID)+" connected"
            ; client connected
          Case 4
            Debug "Client "+Str(clientID)+" disconnected"
            ; client disconnected
          Default
            Debug "Client request"
            RequestLength = ReceiveNetworkData(ClientID, *ReceiveBuffer, 2000)
            ClientRequest.s= PeekS(*ReceiveBuffer,-1,#PB_UTF8)
            Debug "Received: "+ClientRequest.s
            clientrequest=URLDecoder(clientrequest)
            outputrequestformat.s=""
           
            If UCase(Left(clientrequest.s,4))="GET "
              ClientRequest.s=StringField(ClientRequest,2," ")
              ClientRequest.s=Trim(clientrequest,"/")
              NumberOfParameters=CountString(clientrequest.s,"?")
              Debug NumberOFParameters
              Debug StringField(string.s,NumberOfParameters+1,"?")
              Querystring.s="Select"
              QuerystringColumns.s=""
              QuerystringValue.s=""
              outputrequestformat.s="html"
              Querystringend.s="and filename not like '*%'"
              If NumberOfParameters=0
                ClientRequest=clientRequest+"?$format=html"
              EndIf
              NumberOfParameters=CountString(clientrequest.s,"?")
             
             
              For teller=1 To NumberOfParameters+1
                substring.s=StringField(clientrequest,teller,"?")
                If FindString(substring,"=")
                  filtertype.s=LCase(StringField(substring,1,"="))
                  Filtervalue.s=StringField(substring,2,"=")
                Else
                  filtertype="filename"
                  filtervalue.s=substring
                EndIf
                Debug filtertype
                Debug filtervalue
                If filtertype="filename" And Left(filtervalue,1)="*"
                  Querystringend=""
                EndIf
                If Filtertype="$column"
                  QueryStringColumns+","+FilterValue
                ElseIf Filtertype="$format"
                  OutputRequestformat.s=LCase(FilterValue)
                ElseIf filtertype<>""
                  If QueryStringValue<>""
                    QuerySTringValue+" and "
                  EndIf
                  Querystringvalue+Filtertype +" like '"+filtervalue+"%'"
                EndIf
              Next teller
              Querystringcolumns=LTrim(Querystringcolumns,",")
              If QuerystringColumns=""
                QuerystringColumns="*"
              EndIf
              If Querystringvalue=""
                QuerySTringValue="filename like '%'"
              EndIf
              Querystring+" "+QueryStringColumns+" from pdf where "+Querystringvalue+" "+QueryStringEnd+";"         
              outputrequestformat=Trim(outputrequestformat)
              If outputrequestformat<>"json" And outputrequestformat<>"xml" And outputrequestformat<>"text"
                outputrequestformat="html"
              EndIf
              Debug Querystring
              Debug OutputRequestFormat
              ;-----
              Answer.s=ReadDatabase("",Querystring.s,outputrequestformat.s)
            Else
              Debug "no valid request"
              clientrequest.s=""
              Answer.s="NOT VALID"
            EndIf
            Debug "Formatted to: "+ClientRequest.s
           
            *FileBuffer   = AllocateMemory(Len(Answer)+200)
           
            If outputrequestformat="json"
              *BufferOffset = BuildRequestHeader(*FileBuffer, Answer.s, "application/json")
            ElseIf outputrequestformat="html"
              Answer.s="<html><head></head><body><p>"+answer.s+"</p></body></html>"
              *BufferOffset = BuildRequestHeader(*FileBuffer, Answer.s, "text/html")
            ElseIf outputrequestformat="text"
              Answer=ReplaceString(answer.s,"<br>",#CRLF$)
              *BufferOffset = BuildRequestHeader(*FileBuffer, Answer.s, "text/plain")
            ElseIf outputrequestformat="xml"
              *BufferOffset = BuildRequestHeader(*FileBuffer, Answer.s, "text/xml")
            EndIf
            SendNetworkData(ClientID, *FileBuffer, *BufferOffset-*FileBuffer)
            FreeMemory(*FileBuffer)
        EndSelect
      Else
        Delay(20)
      EndIf
    Until quit=1
  EndIf
  FreeMemory(*receiveBuffer)
EndProcedure



I think I am doing something wrong here, but I cannot figure out what it is. Threadsafe is on, I'm using PB 5.62, x86. Any pointers I could look into?


Top
 Profile  
Reply with quote  
 Post subject: Re: Threads influencing eachother?
PostPosted: Wed Jun 13, 2018 2:31 pm 
Offline
Addict
Addict
User avatar

Joined: Fri May 12, 2006 6:51 pm
Posts: 1257
Location: Germany
You need Threadsafe execute and Mutex...
Code:
Procedure.l BuildRequestHeader(*Buffer, text.s, ContentType$)
  eol$=Chr(13)+Chr(10)
  datalength=Len(text.s)
 
  Length = PokeS(*Buffer, "HTTP/1.1 200 OK"+EOL$, -1, #PB_UTF8)                     : *Buffer+Length
  Length = PokeS(*Buffer, "Date: "+FormatDate("%yyyy %mm %dd %hh:%ii:%ss",Date())+EOL$, -1, #PB_UTF8) : *Buffer+Length
  Length = PokeS(*Buffer, "Server: LVPDFWebServer"+EOL$, -1, #PB_UTF8)      : *Buffer+Length
  Length = PokeS(*Buffer, "Content-Length: "+Str(DataLength)+EOL$, -1, #PB_UTF8)    : *Buffer+Length
  Length = PokeS(*Buffer, "Content-Type: "+ContentType$+EOL$, -1, #PB_UTF8)         : *Buffer+Length
  Length = PokeS(*Buffer, #CRLF$, -1, #PB_UTF8)                                     : *Buffer+Length
  Length = PokeS(*Buffer,text.s+#CRLF$,-1,#PB_UTF8)                                 : *Buffer+Length
 
  ProcedureReturn *Buffer
EndProcedure

Global ServerMutex = CreateMutex()

Procedure WebServer(*Parameters.WebServer)
  Protected ServerID
  Protected Port=*Parameters\Port
 
  ClearStructure(*Parameters, WebServer)
  FreeMemory(*Parameters)
 
 
 
  If InitNetwork() = 0
    debugger("Cannot initialize the network !", 0)
    ProcedureReturn
  EndIf
 
  *receiveBuffer=AllocateMemory(10000)
  LockMutex(ServerMutex)
  ServerID = CreateNetworkServer(#PB_Any,port,#PB_Network_TCP|#PB_Network_IPv4)
  UnlockMutex(ServerMutex)
  If ServerID
    Repeat
      LockMutex(ServerMutex)
      sEvent=NetworkServerEvent(ServerID)
      If sEvent
        ClientID=EventClient()
        UnlockMutex(ServerMutex)
        Select sEvent
          Case #PB_NetworkEvent_Connect
            Debug "Client "+Str(clientID)+" connected"
            ; client connected
          Case #PB_NetworkEvent_Disconnect
            Debug "Client "+Str(clientID)+" disconnected"
            ; client disconnected
          Case #PB_NetworkEvent_Data
            Debug "Client request"
            RequestLength = ReceiveNetworkData(ClientID, *ReceiveBuffer, 2000)
            ClientRequest.s= PeekS(*ReceiveBuffer,-1,#PB_UTF8)
            Debug "Received: "+ClientRequest.s
            clientrequest=URLDecoder(clientrequest)
            outputrequestformat.s=""
           
            If UCase(Left(clientrequest.s,4))="GET "
              ClientRequest.s=StringField(ClientRequest,2," ")
              ClientRequest.s=Trim(clientrequest,"/")
              NumberOfParameters=CountString(clientrequest.s,"?")
              Debug NumberOFParameters
              Debug StringField(string.s,NumberOfParameters+1,"?")
              Querystring.s="Select"
              QuerystringColumns.s=""
              QuerystringValue.s=""
              outputrequestformat.s="html"
              Querystringend.s="and filename not like '*%'"
              If NumberOfParameters=0
                ClientRequest=clientRequest+"?$format=html"
              EndIf
              NumberOfParameters=CountString(clientrequest.s,"?")
             
             
              For teller=1 To NumberOfParameters+1
                substring.s=StringField(clientrequest,teller,"?")
                If FindString(substring,"=")
                  filtertype.s=LCase(StringField(substring,1,"="))
                  Filtervalue.s=StringField(substring,2,"=")
                Else
                  filtertype="filename"
                  filtervalue.s=substring
                EndIf
                Debug filtertype
                Debug filtervalue
                If filtertype="filename" And Left(filtervalue,1)="*"
                  Querystringend=""
                EndIf
                If Filtertype="$column"
                  QueryStringColumns+","+FilterValue
                ElseIf Filtertype="$format"
                  OutputRequestformat.s=LCase(FilterValue)
                ElseIf filtertype<>""
                  If QueryStringValue<>""
                    QuerySTringValue+" and "
                  EndIf
                  Querystringvalue+Filtertype +" like '"+filtervalue+"%'"
                EndIf
              Next teller
              Querystringcolumns=LTrim(Querystringcolumns,",")
              If QuerystringColumns=""
                QuerystringColumns="*"
              EndIf
              If Querystringvalue=""
                QuerySTringValue="filename like '%'"
              EndIf
              Querystring+" "+QueryStringColumns+" from pdf where "+Querystringvalue+" "+QueryStringEnd+";"         
              outputrequestformat=Trim(outputrequestformat)
              If outputrequestformat<>"json" And outputrequestformat<>"xml" And outputrequestformat<>"text"
                outputrequestformat="html"
              EndIf
              Debug Querystring
              Debug OutputRequestFormat
              ;-----
              Answer.s=ReadDatabase("",Querystring.s,outputrequestformat.s)
            Else
              Debug "no valid request"
              clientrequest.s=""
              Answer.s="NOT VALID"
            EndIf
            Debug "Formatted to: "+ClientRequest.s
           
            *FileBuffer   = AllocateMemory(Len(Answer)+200)
           
            If outputrequestformat="json"
              *BufferOffset = BuildRequestHeader(*FileBuffer, Answer.s, "application/json")
            ElseIf outputrequestformat="html"
              Answer.s="<html><head></head><body><p>"+answer.s+"</p></body></html>"
              *BufferOffset = BuildRequestHeader(*FileBuffer, Answer.s, "text/html")
            ElseIf outputrequestformat="text"
              Answer=ReplaceString(answer.s,"<br>",#CRLF$)
              *BufferOffset = BuildRequestHeader(*FileBuffer, Answer.s, "text/plain")
            ElseIf outputrequestformat="xml"
              *BufferOffset = BuildRequestHeader(*FileBuffer, Answer.s, "text/xml")
            EndIf
            SendNetworkData(ClientID, *FileBuffer, *BufferOffset-*FileBuffer)
            FreeMemory(*FileBuffer)
          Default
           
        EndSelect
       
      Else
        UnlockMutex(ServerMutex)
        Delay(20)
      EndIf
    Until quit=1
  EndIf
  FreeMemory(*receiveBuffer)
EndProcedure


_________________
My Projects OOP-BaseClass / OOP-BaseClassDispatch / Event-Designer /
PB v3.30 / v5.60 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace


Top
 Profile  
Reply with quote  
 Post subject: Re: Threads influencing eachother?
PostPosted: Wed Jun 13, 2018 3:47 pm 
Offline
Administrator
Administrator

Joined: Fri May 17, 2002 4:39 pm
Posts: 13304
Location: France
Seems like some mutex are missing in the network lib as you shouldn't need this in threaded mode. Moved to bug section for investigation.


Top
 Profile  
Reply with quote  
 Post subject: Re: Threads influencing eachother?
PostPosted: Wed Jun 13, 2018 3:50 pm 
Offline
User
User

Joined: Fri Jul 14, 2006 10:27 pm
Posts: 20
Hi MK-soft,

Threadsafe I understand, but why would I need the mutex? I don't have any shared resources in these two procedures. And those netwerkcommands should be threadsafe (just trying to understand, not to be stubborn or something like that)...

And fred already answered...


Top
 Profile  
Reply with quote  
 Post subject: Re: Threads influencing eachother?
PostPosted: Wed Jun 13, 2018 4:45 pm 
Offline
Addict
Addict
User avatar

Joined: Fri May 12, 2006 6:51 pm
Posts: 1257
Location: Germany
The problem is between
- NetworkServerEvent(ServerID)
- EventClient()

I think EventClient() function ist not threaded...

_________________
My Projects OOP-BaseClass / OOP-BaseClassDispatch / Event-Designer /
PB v3.30 / v5.60 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace


Top
 Profile  
Reply with quote  
 Post subject: Re: Threads influencing eachother?
PostPosted: Wed Jun 13, 2018 5:45 pm 
Offline
Addict
Addict
User avatar

Joined: Wed Dec 23, 2009 10:14 pm
Posts: 2667
Location: Boston, MA
Is this a new bug in v57b1 or existed in v562 and earlier?
Sorry, cannot test right now.

_________________
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum


Top
 Profile  
Reply with quote  
 Post subject: Re: Threads influencing eachother?
PostPosted: Wed Jun 13, 2018 6:05 pm 
Offline
Addict
Addict
User avatar

Joined: Fri May 12, 2006 6:51 pm
Posts: 1257
Location: Germany
It´a old problem by using network-server function on different threads...

I don't say is a bug. Its a problem...

_________________
My Projects OOP-BaseClass / OOP-BaseClassDispatch / Event-Designer /
PB v3.30 / v5.60 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye