工作线程里不要直接改控件。按钮只创建线程池并投递;改标题/表格放在 完成事件 / 空闲事件(界面线程回调)。
最小可跑代码(粘到 main.yc)
窗口需有:按钮开始、标签状态、进度条1(可选,没有就删进度相关行)。
整数 g_池 = 0
整数 g_总数 = 0
整数 g_完成 = 0
逻辑 g_忙碌 = 假
函数 重活 (整数 i) {
// 工作线程:只算,不碰控件
延时(80 + i * 5)
}
函数 任务完成 (整数 任务序号) {
// 界面线程:每个任务结束后进来
g_完成 = g_完成 + 1
标签状态.标题 = "完成 " + 到文本(g_完成) + "/" + 到文本(g_总数)
+ "(刚完成序号 " + 到文本(任务序号) + ")"
如果 (g_总数 > 0) {
进度条1.位置 = (g_完成 * 100) / g_总数
}
}
函数 全部空闲 () {
// 界面线程:池由忙变空闲
如果 (g_忙碌 == 假) {
返回 ()
}
如果 (g_完成 < g_总数) {
返回 ()
}
g_忙碌 = 假
按钮开始.启用 = 真
标签状态.标题 = "全部完成,界面未卡住"
如果 (g_池 != 0) {
关闭线程池(g_池)
g_池 = 0
}
}
函数 按钮开始.单击 (整数 x, 整数 y) {
如果 (g_忙碌) {
返回 ()
}
g_忙碌 = 真
g_完成 = 0
g_总数 = 20
按钮开始.启用 = 假
进度条1.位置 = 0
标签状态.标题 = "投递中…"
g_池 = 创建线程池(0)
如果 (g_池 == 0) {
标签状态.标题 = "创建线程池失败"
g_忙碌 = 假
按钮开始.启用 = 真
返回 ()
}
置线程池完成事件(g_池, &任务完成)
置线程池空闲事件(g_池, &全部空闲)
整数 i
循环(g_总数, i) {
投递任务(g_池, &重活, i)
}
// 立刻返回 —— 绝不在这里 等待线程池
标签状态.标题 = "已投递,窗口应可拖动"
}
函数 主窗口.创建完毕 () {
标签状态.标题 = "点「开始」:后台算,完成事件回写 UI"
}
规则对照
| 错误 | 正确 |
|---|---|
在 重活 里写 标签.标题 = … |
只在 任务完成 / 全部空闲 里改控件 |
按钮里 等待线程池 |
按钮只投递,等空闲事件收尾 |
| 空闲事件一到就关池(投递间隙也可能空闲) | 用 g_完成 == g_总数(或业务完成计数)再收尾 |
API 说明见 多线程支持库。