线程与协程

       本节将全面讲解Lua中的线程实现、协程机制以及在Android平台下的多线程编程实践和优化技巧。

1. 线程基础

1.1 Lua线程概念

Lua本身不直接支持操作系统级线程,但可以通过以下方式实现多线程:

-- Lua原生协程(轻量级线程)
local co = coroutine.create(function() end)

-- 通过C扩展实现真线程(如LuaJIT的ffi)
local ffi = require("ffi")
ffi.cdef[[
    int pthread_create(pthread_t*, const pthread_attr_t*, void*(*)(void*), void*);
]]

-- Android平台通过Java线程交互
local Thread = luajava.bindClass("java.lang.Thread")

注意: 原生Lua是单线程的,多线程需要依赖宿主环境或扩展库

1.2 线程安全

-- 全局变量锁保护
local lock = require("lock")

function threadSafeFunc()
    lock.acquire()
    -- 操作共享资源
    lock.release()
end

-- Android中的线程安全
local runOnUiThread = function(func)
    activity.runOnUiThread(luajava.createProxy("java.lang.Runnable", {
        run = func
    }))
end

2. 线程实现方案

2.1 LuaJIT的FFI线程

-- 使用LuaJIT的FFI调用pthread
local ffi = require("ffi")
ffi.cdef[[
    typedef struct { int dummy; } pthread_t;
    int pthread_create(pthread_t*, void*, void*(*)(void*), void*);
]]

local function threadFunc(arg)
    print("线程运行:", ffi.string(arg))
    return nil
end

local thr = ffi.new("pthread_t[1]")
local arg = ffi.new("char[?]", #"hello", "hello")
ffi.C.pthread_create(thr, nil, threadFunc, arg)

2.2 Android Java线程

-- 创建Java线程
local Thread = luajava.bindClass("java.lang.Thread")
local Runnable = luajava.bindClass("java.lang.Runnable")

local task = Runnable{
    run = function()
        print("在Java线程中执行Lua代码")
        -- 调用Lua函数
    end
}

local thread = Thread(task)
thread:start()

3. 线程通信

3.1 共享内存

-- 使用全局表+锁
sharedData = {
    queue = {},
    lock = require("lock")()
}

-- 生产者线程
function producer()
    while true do
        sharedData.lock:acquire()
        table.insert(sharedData.queue, os.time())
        sharedData.lock:release()
        os.execute("sleep 1")
    end
end

-- 消费者线程
function consumer()
    while true do
        sharedData.lock:acquire()
        if #sharedData.queue > 0 then
            print(table.remove(sharedData.queue, 1))
        end
        sharedData.lock:release()
    end
end

3.2 消息队列

-- Android中的Handler消息机制
local Handler = luajava.bindClass("android.os.Handler")
local Message = luajava.bindClass("android.os.Message")

local handler = Handler{
    handleMessage = function(msg)
        print("收到消息:", msg.obj)
    end
}

-- 子线程发送消息
local thread = Thread{
    run = function()
        local msg = Message.obtain()
        msg.obj = "来自子线程的数据"
        handler:sendMessage(msg)
    end
}

4. Android线程实践

4.1 UI线程操作

-- 安全的UI更新方法
function safeUpdateUI(view, data)
    activity.runOnUiThread(luajava.createProxy("java.lang.Runnable", {
        run = function()
            view:setText(data)
            view:invalidate()
        end
    }))
end

-- 异步任务示例
local AsyncTask = luajava.bindClass("android.os.AsyncTask")
local task = AsyncTask{
    doInBackground = function(params)
        -- 后台执行耗时操作
        return "结果数据"
    end,
    onPostExecute = function(result)
        -- 自动回到UI线程
        textView:setText(result)
    end
}
task:execute()

4.2 线程池管理

-- 使用Java线程池
local Executors = luajava.bindClass("java.util.concurrent.Executors")
local executor = Executors.newFixedThreadPool(4)

-- 提交任务
for i = 1, 10 do
    executor:submit(luajava.createProxy("java.lang.Runnable", {
        run = function()
            print("执行任务"..i)
        end
    }))
end

-- 关闭线程池
executor:shutdown()

5. 线程同步

5.1 互斥锁

-- 简单的Lua锁实现
local lock = {
    acquire = function(self)
        while self.locked do
            os.execute("sleep 0.01")
        end
        self.locked = true
    end,
    release = function(self)
        self.locked = false
    end,
    locked = false
}

-- 使用示例
lock:acquire()
-- 临界区代码
lock:release()

5.2 条件变量

-- 使用Java的同步机制
local Object = luajava.bindClass("java.lang.Object")
local monitor = Object()

-- 等待条件
function waitForCondition()
    synchronized(monitor)
        monitor:wait()  -- 释放锁并等待
    end
end

-- 通知条件
function notifyCondition()
    synchronized(monitor)
        monitor:notifyAll()
    end
end

6. 协程基础

6.1 协程概念

协程是Lua原生支持的轻量级线程,具有以下特点:

-- 创建协程
local co = coroutine.create(function()
    print("协程开始")
    coroutine.yield()
    print("协程恢复")
end)

-- 执行协程
coroutine.resume(co)  -- 输出"协程开始"
coroutine.resume(co)  -- 输出"协程恢复"

6.2 协程状态

local co = coroutine.create(function()
    coroutine.yield("第一次yield")
    return "结束"
end)

print(coroutine.status(co))  -- suspended
coroutine.resume(co)         -- 返回true + "第一次yield"
print(coroutine.status(co))  -- suspended
coroutine.resume(co)         -- 返回true + "结束"
print(coroutine.status(co))  -- dead

7. 协程通信

7.1 数据交换

-- 通过yield和resume传递数据
local consumer = coroutine.create(function()
    while true do
        local data = coroutine.yield()
        print("消费:", data)
    end
end)

coroutine.resume(consumer)  -- 启动协程
for i = 1, 3 do
    coroutine.resume(consumer, "数据"..i)  -- 输出"消费: 数据1"等
end

7.2 双向通信

local co = coroutine.create(function()
    print("协程收到:", coroutine.yield("第一次yield"))
    return "最终结果"
end)

local _, msg = coroutine.resume(co)  -- msg为"第一次yield"
print("主程序收到:", msg)
_, msg = coroutine.resume(co, "回复数据")  -- 输出"协程收到: 回复数据"
print("主程序收到:", msg)  -- "最终结果"

8. 协程应用模式

8.1 生产者-消费者

function producer()
    return coroutine.create(function()
        for i = 1, 3 do
            coroutine.yield("产品"..i)
        end
    end)
end

function consumer(prod)
    while true do
        local _, product = coroutine.resume(prod)
        if not product then break end
        print("消费:", product)
    end
end

consumer(producer())

8.2 协程管道

function filter(prev_co)
    return coroutine.create(function()
        for value in prev_co do
            if type(value) == "number" then
                coroutine.yield(value * 2)
            end
        end
    end)
end

function generator()
    return coroutine.create(function()
        coroutine.yield(1)
        coroutine.yield("a")
        coroutine.yield(2)
    end)
end

local pipeline = filter(generator())
while true do
    local _, val = coroutine.resume(pipeline)
    if not val then break end
    print(val)  -- 输出2, 4
end

9. Android协程实践

9.1 异步任务封装

-- 将异步回调转为协程
function asyncTask(callback)
    local co = coroutine.running()
    callback(function(...)
        coroutine.resume(co, ...)
    end)
    return coroutine.yield()
end

-- 使用示例
local function httpGet(url, callback)
    -- 模拟网络请求
    Timer():schedule(1000, function()
        callback("响应数据")
    end)
end

coroutine.wrap(function()
    local data = asyncTask(function(cb)
        httpGet("https://example.com", cb)
    end)
    print("收到数据:", data)  -- 1秒后输出
end)()

9.2 UI更新协程

-- 安全的UI协程更新
function uiCoroutine(func)
    coroutine.wrap(function()
        -- 后台执行
        local result = {func()}
        
        -- 回到UI线程
        activity.runOnUiThread(luajava.createProxy("java.lang.Runnable", {
            run = function()
                -- 处理结果
                unpack(result)
            end
        }))
    end)()
end

-- 使用示例
uiCoroutine(function()
    local data = asyncTask(httpGet, "url")  -- 后台网络请求
    return function()
        textView:setText(data)  -- UI线程更新
    end
end)

10. 高级协程技术

10.1 协程池

-- 简单的协程池实现
local coPool = {
    pool = {},
    get = function(self)
        for i, co in ipairs(self.pool) do
            if coroutine.status(co) == "dead" then
                table.remove(self.pool, i)
            elseif coroutine.status(co) == "suspended" then
                return co
            end
        end
        return coroutine.create(function() end)
    end,
    recycle = function(self, co)
        table.insert(self.pool, co)
    end
}

-- 使用示例
local co = coPool:get()
coroutine.resume(co, function()
    print("任务执行")
end)
coPool:recycle(co)

10.2 协程调试

-- 协程调用栈追踪
function printCoroutineStack(co)
    print("协程栈追踪:", co)
    local level = 1
    while true do
        local info = debug.getinfo(co, level)
        if not info then break end
        print(string.format("%s:%d in '%s'", 
              info.short_src, info.currentline, info.name or "?"))
        level = level + 1
    end
end

-- 使用示例
local co = coroutine.create(function()
    local function inner()
        printCoroutineStack(coroutine.running())
    end
    inner()
end)
coroutine.resume(co)

11. 性能优化

11.1 协程vs线程

特性 协程 线程
创建开销 极小(~400字节) 较大(~1MB)
切换成本 纳秒级 微秒级
并行性 协作式 抢占式
适用场景 I/O密集型 CPU密集型

11.2 内存管理

-- 避免协程泄漏
local weakTable = setmetatable({}, {__mode = "v"})

function trackedCoroutine(f)
    local co = coroutine.create(f)
    weakTable[co] = true
    return co
end

-- 定期检查泄漏
function checkLeaks()
    for co in pairs(weakTable) do
        if coroutine.status(co) == "dead" then
            weakTable[co] = nil
        end
    end
    print("活跃协程数:", tableCount(weakTable))
end