I’ve found some interesting discoveries.
It seems mutexes mostly work inside coroutines.
But if you use an await inside of a locked area, it’ll break the mutex. Basically, it seems using await inside thread space can lead to inconsistent behavior.
Trying to use an await inside of a thread can sometimes give you the following error (more info on this at the end)
E 0:00:00:0712 coroutines.gd:22 @ start_coroutine(): Class 'GDScriptFunctionState' already exists. <C++ Error> Condition "classes.has(name)" is true. <C++ Source> core/object/class_db.cpp:726 @ _add_class2() <Stack Trace> coroutines.gd:22 @ start_coroutine()
Now, about the coroutines and mutexes.
Here is the latestest testcode I was using:
extends Node2D
var mutex: Mutex
var thread: Thread
var thread2: Thread
var thread3: Thread
func _ready():
mutex = Mutex.new()
#thread = Thread.new()
#thread.start(start_coroutine.bind(1))
#thread2 = Thread.new()
#thread2.start(start_coroutine.bind(2))
#thread3 = Thread.new()
#thread3.start(start_coroutine.bind(3))
for i in 5:
start_coroutine(i)
func start_coroutine(id):
print("Started coroutine")
await get_tree().create_timer(randf_range(0.5, 1.0)).timeout
# Some code
# Changes some index. Critical area
mutex.lock()
print("Critical area... ", id)
for i in randi_range(100000000,100000000):
pass
#await get_tree().create_timer(randf_range(0.1, 0.5)).timeout
print("End critical area... ", id)
mutex.unlock()
# Some code
print("Coroutine done")
Good results. Mutex is working:
Started coroutine
Started coroutine
Started coroutine
Started coroutine
Started coroutine
Critical area... 1
End critical area... 1
Coroutine done
Critical area... 0
End critical area... 0
Coroutine done
Critical area... 4
End critical area... 4
Coroutine done
Critical area... 2
End critical area... 2
Coroutine done
Critical area... 3
End critical area... 3
Coroutine done
But if you un-comment the await inside the start_coroutine
the mutex simply stops working, and all goes crazy.
Results:
Started coroutine
Started coroutine
Started coroutine
Started coroutine
Started coroutine
Critical area... 1
End critical area... 1
Coroutine done
Critical area... 2
Critical area... 0
Critical area... 3
Critical area... 4
End critical area... 2
Coroutine done
End critical area... 0
Coroutine done
End critical area... 3
Coroutine done
End critical area... 4
Coroutine done
Also, using the threads with the await inside can lead to inconsistent errors.
Sometimes it happens, sometimes it doesn’t.
I was using a randf_range()
to create a timer, so maybe when it tries to create two timers with the same value, at the same time, it gives this error. I’m not sure.