我正在编写一个 TCL/Tk 应用程序,它在某个时候有一个最终运行以下循环的按钮:
while {[llength $Queue]>0} {
thread::mutex lock [tsv::set Workers Mutex]
while {[tsv::llength Workers Available]==0} {
thread::cond wait [tsv::set Workers Notify] [tsv::set Workers Mutex]
}
set tid [tsv::lpop Workers Available 0]
thread::mutex unlock [tsv::set Workers Mutex]
set Queue [lassign $Queue item]
thread::send -async $tid "threaded_item $item"
while {[tsv::llength Result Items]} {
display_result {*}[tsv::lpop Result Items]
update
}
}
for {set i 0} {$i<$ThreadCount} {incr i} {
thread::mutex lock [tsv::set Workers Mutex]
while {![tsv::llength Workers Available]} {
thread::cond wait [tsv::set Workers Notify] [tsv::set Workers Mutex]
}
set tid [tsv::lpop Workers Available 0]
thread::mutex unlock [tsv::set Workers Mutex]
thread::release $tid
while {[tsv::llength Result Items]} {
display_result {*}[tsv::lpop Result Items]
}
}
threaded_item
将运行冗长的事情,并将结果附加到 Result Items
TSV(线程共享变量)中,将自身重新添加到 Workers Available
TSV 中,并发送有关存储在 Workers Notify
TSV 中的条件句柄的通知。 Queue
将整个工作负载分成多个份额,第一个循环将这些份额分配给线程,第二个循环耗尽最后分配给每个线程的工作结果并释放它们。
这样我就可以并行化工作负载,原则上它是可行的。问题是循环阻塞了应用程序。我想是因为它是用pthreads-style notification写的,没有考虑TCL的event loop。我认为阻塞的地方是
thread::cond wait
.
在尝试解决这个问题时,我发现了一篇文章更新被认为是有害的。在我的例子中,
update
绝对是在 display_result
完成后出现在屏幕上的更新结果的 hack,它的外观看起来像是没有考虑事件循环的糟糕设计的真实例子。
所以,我想将来自线程的通知与事件循环结合起来。我希望能够暂停/重新启动或中断并停止该过程,以及添加的其他内容。问题是,该怎么做?我应该在“空闲后”运行一些东西吗?如果是的话,那会是什么?如何处理来自线程完成共享的通知?当队列耗尽需要释放线程时,如何处理最后一块?如何防止流程重复启动,以便在调度新作业之前清理已经运行的作业?最好看一个示例/教程,了解如何使用 TCL/Tk 以事件循环友好的方式重写这样的过程。