Will all my NIF functions (of the same module) be called from the same emulator thread?

(Disclaimer: I’m not the most versed developer when it comes to threading, so forgive my ignorance.)

What I need to know is: will all my NIF functions (of the same module) be called from the same emulator thread ?

And… if this question is answered in the documentation, can you point me to it?


Btw, for this matter I found the documentation of the Erlang driver clearer than the one about Erlang NIFs.

Excerpt from documentation about erl_driver.

Drivers are locked either on driver level or port level (driver instance level). By default driver level locking will be used, that is, only one emulator thread will execute code in the driver at a time. If port level locking is used, multiple emulator threads can execute code in the driver at the same time. Only one thread at a time will call driver callbacks corresponding to the same port, though. To enable port level locking, set the ERL_DRV_FLAG_USE_PORT_LOCKING driver flag in the driver_entry used by the driver. When port level locking is used, the driver writer is responsible for synchronizing all accesses to data shared by the ports (driver instances).

Here it’s pretty clear: if I use driver-level locking, my C functions will always be called from the same thread.

Excerpt from documentation about erl_nif.

Threads and concurrency - A NIF is thread-safe without any explicit synchronization as long as it acts as a pure function and only reads the supplied arguments. When you write to a shared state either through static variables or enif_priv_data, you need to supply your own explicit synchronization. This includes terms in process independent environments that are shared between threads. Resource objects also require synchronization if you treat them as mutable.

Not sure that means tbh…

Thank you,
Jonathan

It does not mean your driver C functions will always be called from the same thread. It means your C functions will only be called by one thread at a time.

For NIFs it’s similar to the driver with port level locking, except it’s “Erlang process level locking”. Several threads may execute your NIFs at the same time, but only by one Erlang process at a time (Erlang processes are by nature “single threaded”). This means you are thread safe as long you only access the calling process via its ErlNifEnv* argument. Accessing any other data that may be shared by different Erlang processes (and thereby different threads) will require your own thread synchronization, such as locks, in order to be safe.

7 Likes

Sorry, this did not come out right. I mean of course that each Erlang process can only make one NIF call at a time.
The same NIF can be called by several threads at the same time as long as the calls are made by different Erlang processes.

2 Likes

Thanks for the answer!

Ah. Indeed, I misread. Thanks for pointing this out.