6

我经常只想触发某个函数一次,但我需要从另一个重复调用的函数中触发它。例如,拍摄某物的快照以备后用。我通常通过设置一个全局布尔值来做到这一点。

我想知道我这样做的方式是否实际上是最好的方式?

我似乎记得读过全局变量不好,全局布尔变量更糟!

无论如何,这就是我通常只完成一次触发某个方法的方式:

在我最初的一组变量中......

private var myStatus:Boolean = false;

然后,在经常调用的函数中......

if (!myStatus) {
    doMyFunction();
    myStatus = true;
}

对我来说这似乎很合乎逻辑,但这是正确的吗?

更新:好吧,根据我从您的答案中学到的知识,我现在不是检查全局布尔变量,而是首先检查 XML 节点是否存在(在写入磁盘之前,我将图像存储在 XML 结构中),并且,如果不是,那么我将使用 base64 编码的图像数据附加一个新节点。我仍然设置了一个布尔标志,以便稍后我可以在需要时用用户编辑的图像数据覆盖空白图像。它完美地工作。感谢大家的帮助!

我现在也对在某些情况下使用该特定(线程不安全)系统感到更自在。

4

7 回答 7

7

当你调用一个函数时,它应该做你期望它对你给它的参数做的事情。如果你以完全相同的方式调用一个函数两次,你应该期望该函数给你相同的结果或做同样的事情。

将这种调用一次的依赖项移至多次调用您的函数的逻辑可能会更好。如果您只需要调用一次该函数,则只需调用一次。或者,将不同的参数传递给函数以表明您正在做不同的事情。

于 2008-12-09T23:17:57.307 回答
5

这真的取决于你的意思。如果您的代码将从多个线程中调用,那么您就有一个竞争条件,这可能意味着它doMyFunction可能被多次调用。这是因为不止一个线程可以检查myStatus,看到它是假的,然后调用doMyFunction。您可以通过首先设置变量来稍微改善这种情况:

if (!myStatus) {
    myStatus = true;
    doMyFunction();
}

但这只会缩小问题的窗口,并不能消除它。

要消除竞争条件,您需要一个锁。

于 2008-12-09T23:06:15.867 回答
4

在 C/C++ 中,您通常可以保留这样一个事实,即 doMyFunction() 仅通过使用静态变量封装一次,如下所示:

void doMyFunction() {
     // gets called only once.
     // side effects go here.
}

void functionThatGetsCalledALot() {
    static bool called = false;
    if (!called) {
        doMyFunction();
        called = true;
    }
    // do more stuff
}

这避免了使用全局变量,但具有相同的效果,并且静态变量在其相关的地方被声明,所以很清楚发生了什么。请注意,这不是线程安全的,因此如果您有线程,则需要一个锁。

于 2008-12-09T23:09:57.760 回答
2

它不是线程安全的。这对您来说可能无关紧要,但您确实说过“与语言无关”:您可能不想在 Java 的通用库中使用这种模式。

这是一个很难以与语言无关的方式回答的问题,因为可用的替代方案在很大程度上取决于语言。例如,在 POSIX 上,如果您需要线程安全,您可以使用 pthread_once。在 C 中,您有静态局部变量来将该布尔值排除在全局范围之外。在任何 OO 语言中,如果您正在拍摄“某物”的快照以供以后使用,那么可能有一个与“某物”(或快照)相对应的合适对象,它可以存储标志。

于 2008-12-09T23:09:41.507 回答
0

我认为您的方法没有任何问题。请记住,并不总是“正确”的事情......肯定有错误的事情,但正确的事情可能是主观的,也可能取决于系统的要求。

于 2008-12-09T23:02:28.493 回答
0

我没有看到任何其他方式。关于如何改进这一点,唯一想到的是 - 线程安全。但这仅在您有多个线程调用该函数时才需要。

于 2008-12-09T23:06:13.527 回答
0

在 Perl 5.10 或更高版本中,您将使用state变量。

use 5.010;

sub test{
  state $once = 1;

  if( $once ){
    $once = undef;
    say 'first';
  } else {
    say 'not first';
  }
}

test for 1..5;

输出

第一的
不是第一
不是第一
不是第一
不是第一
于 2008-12-10T20:01:27.937 回答