B4J Question About Classes/Threads

vfafou

Well-Known Member
Licensed User
Longtime User
Hello!
I want to initialize a Class RouteObj, from an instance of the WebSocket Class PushB4A.
As it is mentioned from the server tutorials, WebSocket classes are natively multithreaded.

If I initialize the simple RouteObj Class with...
B4X:
Public Sub Some_Event(ACData As Map)
    Try
        Private RtID As String = ACData.Get("RouteID")
        Private ro As RouteObj
        ro.Initialize(RtID,ro)
    Catch
        Log("Some_Event: " & LastException)
    End Try
End Sub
...where Some_Event is a PushB4A event, where the ro object will run? In the PushB4A thread or in its own thread?

Every RouteObj thread (if it will run in its own one) will have some queries, one timer one list filled with a custom type structure (for sorting) and one threadsafe map.
Is it a must to write Async Queries, especially for the heaviest ones?
Will the timer be accurate?
The map will be changed from whatever threads but no problem as it is threadsafe...
What about the list? Will the list have problem with access from multiple PushB4A threads?
In fact, the list will be changed from an event of PushB4A which will call another event of RouteObj with CallSubDelayed...
I could say that I want to run some "Inter-Thread" processes.

Thank you in advance!
 

vfafou

Well-Known Member
Licensed User
Longtime User
Hello Erel!
Thank you for your response...
This event is raised by the workstations (PCs) that register the routes in the system.
The workstations are connected to the WebSocket server like the mobile devices do.
We could say that a mobile device raises the event!
 
Upvote 0

vfafou

Well-Known Member
Licensed User
Longtime User
The code raises the event, is in an external application using AsyncStreamsText and connects the old VB6 clients with the websocket server.
astmClient_NewData calls CallSubDelayed2(PushService,"SendMessageToCloud",mInput).
SendMessageToCloud raises the RMDigi_Message event.
If the message type is "QQ" then RouteObj is initialized.

The code in the external application:
B4X:
Private Sub astmClient_NewData (Buffer() As Byte)
    Dim RmID As String
    'Dim RmMesg As String 
   
    Dim newDataStart As Int = sbAssemStm.Length
   
    sbAssemStm.Append(BytesToString(Buffer, 0, Buffer.Length, ENCODING))
   
    Dim s As String = sbAssemStm.ToString
    Dim start As Int = 0
   
    For i = newDataStart To s.Length - 1
        Dim c As Char = s.CharAt(i)
            If i = 0 And c = Chr(10) Then '\n...
            start = 1 'might be a broken end of line character
            Continue
        End If

        If c = Chr(10) Then '\n
           
            Try
                mInput = s.SubString2(start, i)
           
                Log(mInput)
               
                RmID   = Main.Str.SplitGetWord(mInput, ",", 3)
                'RmMesg = Main.Str.SplitGetWord(mInput, ",", 4)
               
                CallSubDelayed2(PushService,"SendMessageToCloud",mInput)
                   
            Catch
                Log("ASTM NewData 1: " & LastException)
                Continue
            End Try
               
            start = i + 1
           
        Else If c = Chr(13) Then '\r
            'CallSubDelayed2(Main, mEventName & "_Input", s.SubString2(start, i))
           
            Try
                mInput = s.SubString2(start, i)
               
                Log(mInput)
               
                RmID = Main.Str.SplitGetWord(mInput, ",", 3)
               
                CallSubDelayed2(PushService,"SendMessageToCloud",mInput)
                   
                If i < s.Length - 1 And s.CharAt(i + 1) = Chr(10) Then '\r\n
                    i = i + 1
                End If
            Catch
                Log("ASTM NewData 2: " & LastException)
                Continue
            End Try
            start = i + 1
        End If
    Next
    Try
        If start > 0 Then sbAssemStm.Remove(0, start)
    Catch
        Log("ASTM NewData 3: " & LastException)
    End Try
End Sub

Public Sub SendMessageToCloud(Msg As String)
    wsh.SendEventToServer("RMDigi_Message", CreateMap("message": Msg))
End Sub
The code in PushB4A:
B4X:
Public Sub RMDigi_Message(Data As Map)
    Try
        RMDigiMessage(Data)
    Catch
        Log("Error Ev_RMDigiMessage: " & LastException)
    End Try
End Sub

Public Sub RMDigiMessage(Data As Map)
    Dim RmID As String
    Dim RmMesg As String
    Dim RWMesg As String
    Dim RzMesg As String
   
    Dim mZone As Int
    Dim mQueue As Int
   
    Dim RouteID As String
    Dim RouteStr As String
   
    mText = Data.Get("message")
   
    id       = "RMDigi"
    mType = Utils.str.SplitGetWord(mText, ",", 1)
    mBase = Utils.str.SplitGetWord(mText, ",", 2)
    RmID  = Utils.str.SplitGetWord(mText, ",", 3)
   
    If RmID <> "PING" Then
        If RmID <> "MGU" Then
            RmMesg = Utils.str.SplitGetWord(mText, ",", 4)
        End If
       
        Select Case RmID
           
            Case "QQ"
                RouteID  = Utils.str.SplitGetWord(RmMesg, ";", 1)
                RouteStr = Utils.str.SplitGetWord(RmMesg, ";", 2)
               
                Dim RObj As RouteObj
                RObj.Initialize(RouteID,RouteStr)
           
            Case Else
               
                Select Case mType
                   
                    Case 2
                        RWMesg = Utils.str.SplitGetWord(RmMesg, ";", 1)
                       
                        Select Case RWMesg
                           
                            Case "RT","CL","Z","ZD","RC","RR", _
                                 "021","022","023","024","03", _
                                 "PN","MM","PE","RZ","MSG"
                                 CallSubDelayed3(PushShared, "SendWebClientMessage", RmMesg, RmID)
                                
                            Case "WZ"
                                CallSubDelayed3(PushShared, "SendDirectMessage", RmMesg, RmID)
                           
                            Case "MGP"
                                RzMesg = Utils.str.SplitGetWord(RmMesg, ";", 3)
                                RouteID = Utils.str.SplitGetWord(RmMesg, ";", 2)
                               
                                CallSubDelayed3(PushShared, "SendWebClientMessage", RWMesg & ";" & RzMesg, RmID)
                               
                                Dim OSQL As SQL = Main.oPool.GetConnection
                                Dim stations As List = DBUtils.ExecuteMemoryTable(OSQL, "SELECT CD_AIR FROM exchg_master WHERE ACTIVE > 0 AND TABLET_EXEC = 1 AND CD_AIR <> ? AND CD_AIR IN (?,?,?,?,?)",Array As String(RmID,"21Α","45Α","35Α","59Α","55Α"),0)
                                OSQL.Close
                               
                                For Each row() As String In stations
                                    CallSubDelayed3(PushShared, "SendWebClientMessage", "ANN;" & RouteID & " ΠΡΟΣ " & RmID & " " & DateUtils.TicksToString(DateTime.Now) & ";" & RzMesg, row(0))
                                Next
                               
                        End Select
                       
                    Case 3
                        RWMesg = Utils.str.SplitGetWord(RmMesg, ";", 1)
                       
                        If RWMesg <> "WZ" Then
                            CallSubDelayed3(PushShared, "SendWebClientMessage", RmMesg, RmID)
                        Else
                            CallSubDelayed3(PushShared, "SendDirectMessage", RmMesg, RmID)
                        End If
           
                End Select
               
        End Select
   
    End If
   
    ws.Flush
   
End Sub
 
Upvote 0

vfafou

Well-Known Member
Licensed User
Longtime User
Some_Event was a brief example of what I want to do.
The real event is the RMDigi_Message.
 
Upvote 0

vfafou

Well-Known Member
Licensed User
Longtime User
Will this be bad for performance and response of the server?
What could I do to run the RouteObj instances in separate threads?
 
Upvote 0

vfafou

Well-Known Member
Licensed User
Longtime User
I understand. The events and code in the RouteObj instance will run on the same thread that runs the PushB4A instance.
This is actually good for performance. Each connection, with all the relevant code, will run on a different thread.
Oh... I've been confused... It seems I'm missing something!
All instances of RouteObj are being initialized from only one of the websocket instances.
The desired function is having every RouteObj instance running its own thread.
Is it possible to rewrite the RouteObj class as websocket class without being connected, in order to gain the multithreaded feature?
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Is it possible to rewrite the RouteObj class as websocket class without being connected, in order to gain the multithreaded feature?
No.

All instances of RouteObj are being initialized from only one of the websocket instances.
The desired function is having every RouteObj instance running its own thread.
It is not possible. Use the asynchronous SQL commands. The commands will be executed on multiple background threads.
 
Upvote 0

vfafou

Well-Known Member
Licensed User
Longtime User
Hello Erel!
Thank you for your patience about me!
I definitely will use async SQL, but every external device request will make changes to the list object of the RouteObj class for one instance every time but may have multiple concurrent requests for different instances. That's the reason I want to have separate thread for every RouteObj.
Is it safe to have all RouteObj instances to only one thread that is running only one websocket instance? I have to tell you that every RouteObj instance has a timer running!
 
Last edited:
Upvote 0
Top