Hi all,
in my B4J server app I have a map containing data that can be modified from 3 different proceesses. One in a timer in the main thread and other in Server.Handler and WebSocket.
The code is something like this stupid sample:
B4X:
x=mymap.get(credits)
x=x+5
mymap.put(credits,x)
I wonder if 2 events may occour in the same moment and create errors.
Is it a good solution to manage a global flag "MapBusy" like this ?
B4X:
Do while MapBusy is true
Loop
MapBusy=true
..... works with the map
MapBusy=false
To protect the Map from concurrent access by websockets you must use Srv.CreateThreadSafeMap. This, of course, does not protect by access from the timer event.
No, definitely not! @LucaMs suggestion is best in this case but in the absence of that you could make things thread safe by using a Lock object from my Threading library. The reason your code is not thread safe is that testing and setting the flag in code is not an atomic (uninterruptible) operation and cannot be made so. This means that your thread can test the flag, see it False and then be suspended to let another thread run before setting the flag True. Another thread can then see the flag is False and also assume it can access the map so potentially causing problems.
Threading problems are easy to create but notoriously difficult to debug so asynchronous code needs to be very carefully designed in the first case or tragedy may ensue.
Your All-in-One Learning Portal: GeeksforGeeks is a comprehensive educational platform that empowers learners across domains-spanning computer science and programming, school education, upskilling, commerce, software tools, competitive exams, and more.
Thank you guys, I have read that article but I'm still confused:
I create a Public ThreadSafeMap in the main code and then ?
How to lock the map between a get and a put ?
How can the second thread know that I have finished or I'm still working with the map ?
Thank you guys, I have read that article but I'm still confused:
I create a Public ThreadSafeMap in the main code and then ?
How to lock the map between a get and a put ?
How can the second thread know that I have finished or I'm still working with the map ?
You don't, the Map ensures that get and put are atomic operations. In a normal Map they are not necessarily atomic as they both deal with locating or adding a key then dealing with a value. Note that if you do a put then a get you are not guaranteed that you get back the same value as you put as another thread might have changed it.
Also a ThreadSafeMap enables safe iteration of the values or keys by means of the Values and Keys methods in the map without another thread's actions changing the Map in mid iteration. What you get is a list of the key and values at the time you made the call. Note again that another thread can add or remove keys and values without your knowledge.
The corollary of the above two paragraphs is that you still have to code in the knowledge that other threads might alter the map, but that they will do it in a thread safe manner.
Assuming another thread might also change 'credits' then yes, it is unsafe. You need to lock a shared resource if you are performing non-atomic operations on it. For example if you are incrementing or decrementing a variable accessed from different threads you would need to use a Lock to make that thread safe.
B4X:
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Dim Lock1 As Lock 'from Threading library
Lock1.Initialize(False) ' unlocked
End Sub
Sub ChangeCredits ' both/all threads must do this
Lock1.Wait 'wait for unlock and then claim lock as an atomic operation
x=mymap.get(credits)
x=x+5
mymap.put(credits,x) 'shared mymap declared somewhere
Lock1.Unlock ' unlock the lock to free access to other threads using Lock1
End Sub
However you only need to do this if two different threads are going to alter the same key:value pair in the map. One updating it and the other just reading it would usually be safe.