diff options
| author | ruki <[email protected]> | 2025-11-04 00:46:52 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2025-11-07 15:01:56 +0800 |
| commit | 4db91f0a96177559363877207357c51485221546 (patch) | |
| tree | a1effc518b2aae4fb989595d857d873c40adc0d8 | |
| parent | 70624314ebcdedbd5e2dd5e51542a33d38f182bc (diff) | |
lock/unlock task queue
| -rw-r--r-- | xmake/core/base/private/async_task.lua | 40 |
1 files changed, 32 insertions, 8 deletions
diff --git a/xmake/core/base/private/async_task.lua b/xmake/core/base/private/async_task.lua index d90579bc1..676f2b226 100644 --- a/xmake/core/base/private/async_task.lua +++ b/xmake/core/base/private/async_task.lua @@ -34,9 +34,10 @@ local is_started = false -- the task event and queue local task_event = nil local task_queue = nil +local task_mutex = nil -- the asynchronous task loop -function async_task._loop(event, queue, is_stopped, is_diagnosis) +function async_task._loop(event, queue, mutex, is_stopped, is_diagnosis) local os = require("base/os") local function dprint(...) @@ -69,12 +70,22 @@ function async_task._loop(event, queue, is_stopped, is_diagnosis) dprint("async_task: started") while not is_stopped:get() do if event:wait(-1) > 0 then + + -- fetch all tasks from queue at once + local cmds = {} + mutex:lock() while not queue:empty() do local cmd = queue:pop() if cmd then - _runcmd(cmd) + table.insert(cmds, cmd) end end + mutex:unlock() + + -- execute tasks without holding lock + for _, cmd in ipairs(cmds) do + _runcmd(cmd) + end end end dprint("async_task: exited") @@ -82,13 +93,14 @@ end -- start the asynchronous task function async_task._start() - assert(task_queue == nil and task_event == nil) + assert(task_queue == nil and task_event == nil and task_mutex == nil) task_event = thread.event() task_queue = thread.queue() + task_mutex = thread.mutex() local task_is_stopped = thread.sharedata() local task_thread = thread.new(async_task._loop, { name = "core.base.async_task", internal = true, - argv = {task_event, task_queue, task_is_stopped, option.get("diagnosis")}}) + argv = {task_event, task_queue, task_mutex, task_is_stopped, option.get("diagnosis")}}) local ok, errors = task_thread:start() if not ok then return false, errors @@ -99,7 +111,10 @@ function async_task._start() is_stopped = true -- Perhaps the thread hasn't started yet. -- Let's wait a while and let it finish executing the tasks in the current queue. - if not task_queue:empty() then + task_mutex:lock() + local is_empty = task_queue:empty() + task_mutex:unlock() + if not is_empty then task_event:post() os.sleep(300) end @@ -141,10 +156,13 @@ function async_task.cp(srcpath, dstpath, opt) -- post task srcpath = path.absolute(tostring(srcpath)) dstpath = path.absolute(tostring(dstpath)) + task_mutex:lock() task_queue:push({kind = "cp", srcpath = srcpath, dstpath = dstpath}) + local queue_size = task_queue:size() + task_mutex:unlock() if opt.detach then -- We cache some tasks before executing them to avoid frequent thread switching. - if task_queue:size() > 10 then + if queue_size > 10 then task_event:post() end else @@ -166,10 +184,13 @@ function async_task.rm(filepath, opt) -- post task filepath = path.absolute(tostring(filepath)) + task_mutex:lock() task_queue:push({kind = "rm", filepath = filepath}) + local queue_size = task_queue:size() + task_mutex:unlock() if opt.detach then -- We cache some tasks before executing them to avoid frequent thread switching. - if task_queue:size() > 10 then + if queue_size > 10 then task_event:post() end else @@ -191,10 +212,13 @@ function async_task.rmdir(dir, opt) -- post task dir = path.absolute(tostring(dir)) + task_mutex:lock() task_queue:push({kind = "rmdir", dir = dir}) + local queue_size = task_queue:size() + task_mutex:unlock() if opt.detach then -- We cache some tasks before executing them to avoid frequent thread switching. - if task_queue:size() > 10 then + if queue_size > 10 then task_event:post() end else |
