【问题标题】:What's the best way to prevent a proc reenry in Tcl?在 Tcl 中防止 proc reenry 的最佳方法是什么?
【发布时间】:2021-03-10 17:22:05
【问题描述】:

Tcl 有信号量之类的东西吗?我需要防止重新进入某个程序。这样的事情在大多数情况下都会起作用:

set inside_A 0
proc A {} {
    global inside_A
    if { $inside_A } {
        return "Ouch!"
    }
    incr inside_A
    ...
    incr inside_A -1
}

但是,这是不可靠的,因为块检查和增量不是原子的。 Tcl 是否有类似信号量的东西来可靠地防止重入?

【问题讨论】:

  • 您是否试图阻止函数的递归调用?还是只能调用一次?
  • @Shawn,这个函数是从 GUI 间接调用的,并且足够快的点击序列被同时调用,根据应用程序逻辑它当然不应该这样做。我无法控制点击次数;我唯一的办法就是拒绝重新进入。

标签: concurrency tcl semaphore


【解决方案1】:

每个 Tcl interp 在单个线程中运行。因此,在检查和增量之间没有任何可能调用您的 proc A。这意味着您概述的方法是安全的。

事实上,没有什么可以调用proc A,除非它通过调用一个可以回调A的proc,通过yield if作为协程运行,或者通过运行update来允许这种情况发生。后一种选择通常是糟糕的设计,应该尽可能避免。

当 A 作为协程运行时,必须特别小心。协程可能会重新启动,这将阻止最终减量运行。这样就不可能再给 A 打电话了。

【讨论】:

  • 如果你创建了两个调用同一个过程的协程,这个过程不会有重入问题,除非它使用全局变量做一些不适合这样使用的事情。过程调用具有独立的局部变量。
  • 我的协程评论是关于启动一个与当前正在运行的协程同名的协程。这将删除旧的协程,剥夺它完成 proc A 的机会。
  • @SchelteBron,唉,事实并非如此。这个特殊的 Tcl 解释器是 Qt 应用程序的一部分,它允许并发(事实上,它在它上面茁壮成长)。解释器对象必须是唯一的。 99% 的情况下这不是问题,但是一旦在蓝月亮中,相同的非重入过程会被击中两次。所以这个问题。
  • 那么该应用程序所做的事情与 Tcl 的设计原则不一致。我怀疑这会导致比两次运行不可重入过程更严重的问题,因为 Tcl 不是以这种方式工作的。而且很明显,Tcl 没有针对不可能的事情的保护方法。
  • 顺便说一句,伙计们,发现 if { [incr my_semaphore] > 1 } 可以解决问题。
猜你喜欢
  • 2011-01-07
  • 2012-09-11
  • 2013-03-25
  • 2016-12-19
  • 1970-01-01
  • 2015-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多