erl_nif_thread and erlang process communication - erlang

Can we communicate with erl_nif thread created and normal erlang process? We can send messages from nif thread to erlang process using nif_send but can nif thread receive messages from any erlang process like normal erlang process do?

No, a thread created with enif_thread_create is not an Erlang process and cannot receive messages.
You are probably trying to achieve too much with your NIF and might consider writing a linked in driver instead, which can send messages and receive messages from Erlang.
Alternatively, you could use a conditional variable and/or a pipe in your native thread to wait for an event which would be generated by a NIF function called from the emulator whenever the message you are expecting is received. Indeed, unlike linked in drivers, you cannot use the select interface from the emulator.

Related

Erlang IO blocking native calls best practices

I've done a lot of reading lately about calling my C code from Erlang. My C code will be making a remote call and I expect to have a timeout of ~10 seconds. In order to keep Erlang responsive and handle additional requests while someone else is waiting for the initial call to C, what are the best practices in 2022?
We can use async port drivers or a NIF with ERL_NIF_DIRTY_JOB_IO_BOUND to run it on the dirty IO scheduler.
My understanding is that the async port driver would be the best option, but looking for more insight here.
Let's say we have an Erlang web server handling two callers A and B. A makes a call which then enters into C and blocks for 10 seconds. While that is waiting, B makes their call which will also need to call C. With an async port driver and a dirty IO NIF what are the differences in execution and blocking? Will B get blocked in Erlang, waiting for the port driver or NIF to be ready to start working on this new request (if that's a thing), or waiting for an available thread (as I understand the async port driver will use its own single thread (unless I do something else to spawn another thread)? And the NIF would use a threadpool).
If we have even more callers calling in where will we bottleneck?
As you can see I have quite a few questions and would highly appreciate help from those with Erlang familiarity!

Qpid Erlang Module

I am newbie to erlang but managed to get the ActiveMQ talking to my erlang shell using qpid pronton c library as, which is working well and i am getting messages from queue itself on my erlang shell and vice versa.
qpidpn:subscribe("amqp://localhost/topic://xxx").
qpidpn:publish(#{address => "amqp://127.0.0.1/topic://xxx", body => "hello"}).
Now, i want to implement the same above stated code using .erl file with some function getting invoked everytime we have new message on the queue and i can take further action of returning the same to origin.
You can implement gen_server, as seems the messages are coming from some MQ. So, you can get the messages in handle_info. Once there you can do whatever you want to do with them.
Well, it all depends on how your subscriber is implemented (is it another process, TCP listener, do you use gen_event behaviour, does it decode any data for you .... ).
Since you are using AMQP protocol for communication, you could use RabbitMQ as client. You would get whole AMQP implementation (with all responses to your broker), and some model for getting messages or subscribing to channels. Code-base is mature, whole project is stable, and most of logic is written for you, so I would strongly recommend using this approach.
The "invoked everytime we have new message on the queue" is somewhat explained in subscibe to que section.

Erlang receive message -- how is it done internally?

How is the receive message implemented internally in erlang runtime?
When the process is waiting for a message, the execution hang on the receive.
The receive is done via blocking IO, or asynchronous IO ?
If former, then it means the OS thread is blocked and if there are many process hang on receiving, the performance is bad in reason of thread context switch and also may reach the operation system's thread limitation.
Erlang processes are not corresponded to OS threads or processes. They are implemented as internal structures of Erlang VM and they are scheduled by Erlang VM. The number of OS threads which are started by Erlang VM by default is equal to CPU number. When the Erlang process is waiting for a message no one OS process or thread is blocked.

Erlang e Thrift

I want to make a Windows Service using Erlang and Thrift.
The service will have a single thread listening in a port (socket communication) and send request to a worker's thread. The Windows Service have to response quickily (milisencods) and the throughput is mandatory. (requests per second)
The workers thread will communicate each other. I think in Earlang to resolve this issue.
So i think erlang+thrift will work good. Am I right? Any suggestions?
Your solution is reasonable. To bring you up to speed i would suggest reading up on gen_server, supervisor, application.
Thrift will generate stub files which by compiling will yield you a transport/acceptor. It's up to you to provide both the thrift api and the handler for this api.
Moreover be advised not to synchronize alot between processes if you need fast response times (ie. dont design your solution around synchronizing calls)

Threaded Erlang C-Node(cnode) Interoperability howto?

I am at a point in my Erlang development where I need to create a C-Node (see link for C-Node docs). The basic implementation is simple enough, however, there is a huge hole in the doc.
The code implements a single threaded client and server. Ignoring the client for the moment... The 'c' code that implements the server is single threaded and can only connect to one erlang client at a time.
Launch EPMD ('epmd -daemons')
Launch the server application ('cserver 1234')
Launch the erlang client application ('erl -sname e1 -setcookie secretcookie') [in a different window from #2]
execute a server command ('complex3:foo(3).') from the erlang shell in #3
Now that the server is running and that a current erlang shell has connected to the server try it again from another window.
open a new window.
launch an erlang client ('erl -sname e2 -setcookie secretcookie').
execute a new server command ('complex3:foo(3).').
Notice that the system seems hung... when it should have executed the command. The reason it is hung is because the other erlang node is connected and that there are no other threads listening for connections.
NOTE: there seems to be a bug in the connection handling. I added a timeout in the receive block and I caught some errant behavior but I did not get them all. Also, I was able to get the cserver to crash without warnings or errors if I forced the first erlang node to terminate after the indicated steps were performed.
So the question... What is the best way to implement a threaded C-Node? What is a reasonable number of connections?
The cnode implementation example in the cnode tutorial is not meant to handle more than one connected node, so the first symptom you're experiencing is normal.
The erl_accept call is what accepts incoming connections.
if ((fd = erl_accept(listen, &conn)) == ERL_ERROR)
erl_err_quit("erl_accept");
fprintf(stderr, "Connected to %s\n\r", conn.nodename);
while (loop) {
got = erl_receive_msg(fd, buf, BUFSIZE, &emsg);
Note that, written this way, the cnode will accept only one connection and then pass the descriptor to the read/write loop. That's why when the erlang node closes, the cnode ends with an error, since erl_receive_msg will fail because fd will point to a closed socket.
If you want to accept more than one inbound connection, you'll have to loop accepting connections and implement a way to handle more than one file descriptor. You needn't a multithread programme to do so, it would probably be easier (and maybe more efficient) to use the poll or select syscall if your OS supports them.
As for the optimum number of connections, I don't think there is a rule for that, you'd need to benchmark your application if you want to support high concurrency in the cnode. But in that case it would probably be better to re-engineer the system so that erlang copes with the concurrency, alleviating the cnode from that.

Resources