73 lines
1.7 KiB
GDScript
73 lines
1.7 KiB
GDScript
class_name ConditionalVariable
|
|
|
|
## Naive implementation of a conditional variable for multi-threading
|
|
var _mutex : Mutex
|
|
var _waiting_queue : Array[Lock]
|
|
|
|
func _init():
|
|
self._mutex = Mutex.new()
|
|
self._waiting_queue = []
|
|
|
|
func wait(lock : LockBase):
|
|
var thread_lock : Lock = Lock.new()
|
|
thread_lock.lock()
|
|
|
|
self._mutex.lock()
|
|
self._waiting_queue.push_back(thread_lock)
|
|
self._mutex.unlock()
|
|
|
|
lock._unlock_and_store_recursion_depth()
|
|
thread_lock.lock()
|
|
lock._lock_and_restore_recursion_depth()
|
|
|
|
thread_lock.unlock()
|
|
|
|
func wait_pred(lock : LockBase, stop_waiting : Callable):
|
|
while !stop_waiting.call():
|
|
self.wait(lock)
|
|
|
|
func wait_for(lock : LockBase, time_sec : float) -> bool:
|
|
var thread_lock : Lock = Lock.new()
|
|
thread_lock.lock()
|
|
|
|
self._mutex.lock()
|
|
self._waiting_queue.push_back(thread_lock)
|
|
self._mutex.unlock()
|
|
|
|
var notified = RefValue.Set(true)
|
|
var on_timeout = func():
|
|
notified.v = false
|
|
thread_lock.unlock()
|
|
self._mutex.lock()
|
|
self._waiting_queue.erase(thread_lock)
|
|
self._mutex.unlock()
|
|
|
|
var timer = GDRx.get_tree().create_timer(time_sec)
|
|
timer.connect("timeout", on_timeout)
|
|
|
|
lock._unlock_and_store_recursion_depth()
|
|
thread_lock.lock()
|
|
lock._lock_and_restore_recursion_depth()
|
|
|
|
if notified.v:
|
|
timer.disconnect("timeout", on_timeout)
|
|
|
|
thread_lock.unlock()
|
|
return notified.v
|
|
|
|
func notify(n = 1):
|
|
self._mutex.lock()
|
|
for __ in range(n):
|
|
if self._waiting_queue.is_empty():
|
|
break
|
|
var next : Lock = self._waiting_queue.pop_front()
|
|
next.unlock()
|
|
self._mutex.unlock()
|
|
|
|
func notify_all():
|
|
self._mutex.lock()
|
|
while not self._waiting_queue.is_empty():
|
|
var next : Lock = self._waiting_queue.pop_front()
|
|
next.unlock()
|
|
self._mutex.unlock()
|