So I’m brand new at multi-threading and I basically want to lock access to a global variable to all other threads while one task writes to it. I’m looking at the documentation Multi-Threading · The Julia Language and I can’t make heads or tail as to what “a” is supposed to mean in
lock(a) do
use(a)
end
If I have a variable MyGlobal and I’m trying to update a field:
function update_global_field(x)
global MyGlobal
MyGlobal.field = x
end
How do I get a task to write to this field and other tasks to read from this field without race conditions? I tried
lock(MyGlobal) do
update_global_field(x)
end
but that didn’t work.
1 Like
You can’t lock arbitary things.
You can only lock things that implement the lock
method.
Which predominantly is subtypes of AbstractLock
So do a
using Base.Threads
const my_global_lock = ReentrantLock()
lock(my_global_lock) do
update_global_field(x)
end
2 Likes
So how do I use this lock to stop other functions from reading this global variable until I’m done writing to it? What did “my_global_lock” actually lock?
It is a lock. It didn’t lock anything. It is a lock, it is the thing that is locked.
lock(my_global_lock)
locked my_global_lock
If some other thread tried to do lock(my_global_lock)
then it would be blocked.
You often will want to pair a lock with a variable (or sometimes a set of variables, or sometimes a part of a value like a column in an array or even entry with a given hash of its index or …).
So the basic way you would to is:
using Base.Threads
const my_global_lock = ReentrantLock()
my_global_value = nothing
function set_value!(x)
lock(my_global_lock) do
global my_global_value
my_global_value = x
end
end
function get_value(x)
return lock(my_global_lock) do
return my_global_value
end
end
then if you only access my_global_value
via set_value!
and get_value
and never directly then you are safe.
Though realistically you want to actually avoid global mutable state;
and avoid situations where you need to share memory between threads, as much as possible.
This kind of thing is fine maybe if its a config, that is rarely read or set,
but a problem if its in your hot-loop.
Since locking and unlocking is expensive.
4 Likes
Oooooooh! That makes sense!
I’m very familiar with trying to avoid a global mutable state, so it is only being updated once a day. It’s just that there’s a lot of background work that happens while updating so I don’t want to hold up other api calls.
I actually start up another task in the backround that runs concurrently, but I DO need the other calls to wait for the split-second it takes to transfer these results to the global state. Normally this isn’t an issue (the “dangerous” update code is very short and likely to happen between calls). I just want to be SURE that it’s safe so I need to use locks.
1 Like
yep that sounds like a great use for locking.