Using Dictionaries in Thread

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By orosmatthew

In the documentation on Thread safe APIs in the Godot Docs, it says that Dictionaries and Arrays are thread safe when reading and writing but not in changing the size. Is this anytime an array is in a thread? As an example:

def this_is_a_thread():
    var myDict = {some:thing}
    myDict[other] = 27

If this function is called as a thread, does creating then adding an element to a dictionary allowed or not? The doc goes on to say that it requires locking a mutex. Would this then be the proper way to do it?

def this_is_a_thread():
    var mutex = Mutex.new()
    mutex.lock()
    var myDict = {some:thing}
    myDict[other] = 27
    mutex.unlock()

Is this the correct way to accomplish all this or am I just completely wrong because the engine does not give me any warnings or erros that anything is wrong but the docs say otherwise unless I’m mistaken.

Thank you for any replies.

:bust_in_silhouette: Reply From: Zylann

You don’t need a mutex just because you use dictionaries or arrays in a thread. The point becomes relevant only if you can access the same dictionary or array from two threads at once (i.e the main thread and one you created).

Containers are shared, they behave like references (i.e you pass it to a function, that function can modify it and the caller will have it modified too).
I think the doc says it is thread-safe because when Godot containers are accessed from two threads, they perform copy-on-write. That is, the container is made unique to the thread which wrote to it, which sort of “breaks” the reference but allows it to continue working on the data without need for explicit synchronization. It’s useful in the sense that the thread would do its work on the data as it was when the work started. It’s like copying the arguments, but only when strictly necessary.

But sometimes your thread might expect the main thread to modify the data on which it works on. If you don’t want copy-on-write to happen and keep the reference, only then, it makes sense to use a mutex.
For example:

var dict = {"foo": 42}
var mutex = Mutex.new()

# This runs in the main thread
func _process(delta):
	# Need to lock for the duration of access
	mutex.lock()
	dict.foo += 1
	print(dict.foo)
	mutex.unlock()


func runs_in_another_thread():
	# The main thread might be using the dictionary,
	# so we lock to wait for ownership
	mutex.lock()
	dict.foo = 0
	mutex.unlock()

Thank you so much! This is the answer I was looking for :smiley:

orosmatthew | 2019-03-02 00:38