Communication between threads

Communication between threads can be tedious to get right. With a ZeroMQ library, you can easily reuse the previous code to move from the network to interprocess communication merely by changing the transport protocol in the connection string. The LuaZMQ library incorporates simple thread control capabilities but you're free to use any libraries to manage threads.

Note that the Lua language contains coroutines to achieve cooperative multitasking, except that everything is processed in a single thread relying on explicit scheduling. It means that only one CPU core is used by your application.

This recipe will give you basic insight in to parallel processing of information in the Lua language.

You'll be sending the well known filling text Lorem ipsum to the reply side and it'll append dolor sit amet in the end. The resulting text will be sent back to the request side and displayed on the screen.

Getting ready

You can view this recipe as a simple mashup of the request-reply model into one Lua script, while the request part is processed in parallel to the reply part.

How to do it…

In this case, the whole thread code for the request part will be stored in a string variable that will be processed in another thread:

local req = [[
  local name = unpack(arg)
  local socket,msg = assert(context.socket(zmq.ZMQ_REQ))
  local result, msg = assert(socket.connect("inproc://test1"))
  local poll = zmq.poll()

  poll.add(socket, zmq.ZMQ_POLLIN, function(socket)
    local result = socket.recvAll()
    if result then
      print(name, string.format("Recieved data: %q", result))
    end
  end)

  socket.send("Lorem ipsum")
  poll.start()
  socket.close()
]]

As you can see, there's not a single line that would explicitly say that this code will be processed in a thread.

  1. You can move on to the Reply part. The following code will look incredibly similar to the code from previous recipes. This is a good example of the ZeroMQ library's versatility:
    local zmq = require 'zmq'
    local context, msg = assert(zmq.context())
    local socket,msg = assert(context.socket(zmq.ZMQ_REP))
    local result, msg = assert(socket.bind("inproc://test1"))
    local poll = zmq.poll()
    
    poll.add(socket, zmq.ZMQ_POLLIN, function(socket)
      local result = socket.recvAll()
      if result then
        print("Reply part",
          string.format("Recieved data: %q", result))
        socket.send(result.." dolor sit amet")
      end
    end)
  2. The only difference is the transport used. Instead of using the TCP transport protocol, there's an in-process communication transport.
  3. The next steps will consist of starting a new thread with the Request part. The main thread with the reply part will wait until it gets a request to reply. You can create a new thread with the context.thread function, which expects at least one parameter with the thread code in a single string. You can add another parameter that will be added into the thread global argument list.
    local thread = context.thread(req, 'Request part')
    poll.start()
  4. The last two lines will ensure that the main thread will wait until the thread closes properly. Without this, you'd get thread abortion, which is sometimes called Parent thread kills its children. It sounds horrible as it's a sign of bad application design.
    thread.join()
    socket.close()

How it works…

This recipe uses inproc or in-process transport to communicate with the request-reply pattern. Almost every aspect of communication remains the same except that the ZeroMQ library uses the shared memory region to transfer messages between threads. This works exceptionally well even without tedious synchronization routines. By using the push-pull socket types instead of request-reply, you can easily create a distributed processing system with a few lines of code or even combine it with the pgm transport protocol to achieve distributed computing on more than one computer.

Threads are created with the context.thread function, where the first argument is always a thread code. LuaZMQ will create a new independent Lua state that shares only the context object. The context object is thread-safe; therefore, it can be shared among all threads.

Optionally, you can add numerical or string variables, which will be available to the thread code via the global arg variable. This emulates a situation where you execute the Lua script with arguments.

The only tricky part is thread management. Before closing your main process, it should always wait for its threads to finish up using the thread.join function.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.165.62