1. ホーム
  2. スクリプト・コラム
  3. ルア

チャックルアにおけるマルチスレッド入門

2022-02-09 04:41:53

chuck-luaはアクターモードのスレッドモデルをサポートしています。cthread.newでスレッドを作成し、cthread.sendmailでスレッドにメッセージを送信することができます。

chuck-luaはskynetのようなフレームワークとは異なり、マルチスレッドのタスク/メッセージスケジューリングを提供しません。各スレッドは、他のスレッドから送られたメッセージをキャッシュするためのシンプルなスレッドメールボックスを維持します。

以下は、簡単なマルチスレッドサーバーの例です。

mtserver.lua

local chuck = require("chuck")
local engine = require("distri.engine")
local socket_helper = chuck.socket_helper
local Distri = require("distri.distri")
local cthread = chuck.cthread

local worker 

function on_new_client(fd)
  cthread.sendmail(worker,{fd})
end

local fd = socket_helper.socket(socket_helper.AF_INET,
                 socket_helper.SOCK_STREAM,
                 socket_helper.IPPROTO_TCP)
socket_helper.addr_reuse(fd,1)

local ip = "127.0.0.1"
local port = 8010

if 0 == socket_helper.listen(fd,ip,port) then
  print("server start",ip,port)
  local server = chuck.acceptor(fd)
  server:Add2Engine(engine,on_new_client)
  Distri.Signal(chuck.signal.SIGINT,Distri.Stop) 
  worker = cthread.new("distri/test/worker.lua")
  Distri.Run()
end



worker.lua

local chuck = require("chuck")
local socket = require("distri.socket")
local engine = require("distri.engine")
local clone = chuck.packet.clone
local cthread = chuck.cthread
local Distri = require("distri.distri")

-- Set the mail processing function
cthread.process_mail(engine, function (sender,mail)
  local fd = table.unpack(mail)
  local s = socket.stream.New(fd)
  if s:Ok(4096,socket.stream.decoder.rawpacket(),function (_,msg,errno)
    if msg then
      s:Send(clone(msg))
    else
      s:Close(errno)
      s = nil
    end
  end) then
    s:SetRecvTimeout(5000)
  else
    s:Close()
  end 
end)

Distri.Run()



この例はシンプルで、メインスレッドがリスナーを起動し、スレッドを作成し、接続を受けたらワーカスレッドにfdを送信します。

チャックルアスレッドの詳細を簡単に紹介します。

各スレッドは別々の仮想マシン上で動作するため、ある仮想マシンから他のスレッドにメッセージで直接オブジェクトを送信することはできません。現在sendmailは、メッセージとして渡されたluaテーブルをトランスポート可能なオブジェクトとしてシリアライズし、ターゲットスレッドで受信した後、このスレッドの仮想マシンのluaテーブルに再変換しています。

cthread.sendmailでターゲットスレッドにメッセージを送信する場合、バッファ行がターゲットのメールボックスに到達するとブロックされます。メールメッセージを処理することを期待するすべてのスレッドは、メッセージコールバック関数を設定するために cthread.process_mail を呼び出す必要があります。そうしないと、メッセージ送信スレッドが永久にブロックされるかもしれません。

スレッドはjoinモードを使って作成され、作成者はcthread.joinでスレッドが終了するのを待つことができます。

今回の記事は以上です。