¿Cómo activar una función una vez, y solo una vez ...?

votos
6

A menudo quiero activar una determinada función solo una vez, pero necesito activarla desde otra función que recibe repetidas llamadas. Por ejemplo, tomar una instantánea de algo para usarlo más tarde. Normalmente lo hago estableciendo un booleano global.

Me pregunto si la forma en que lo hago es en realidad la mejor manera.

¡Me parece recordar que las variables globales son malas y las variables booleanas globales son aún peores!

De todos modos, así es como generalmente logro desencadenar cierto método solo una vez:

En mi conjunto inicial de variables ...

private var myStatus:Boolean = false;

Luego, dentro de la función que se llama a menudo ...

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

Me parece bastante lógico, pero ¿es lo correcto ?

ACTUALIZACIÓN : Bueno, basándome en lo que aprendí de sus respuestas, en lugar de verificar una variable booleana global, primero compruebo si el nodo XML existe (estoy almacenando las imágenes dentro de una estructura XML antes de que se produzca cualquier escritura en el disco), y si no lo hace, añado un nuevo nodo con los datos de imagen codificados en base64. Todavía configuro un indicador booleano para luego poder sobreescribir la imagen en blanco con los datos de imagen editados por el usuario si fuera necesario. Funciona perfectamente ¡Gracias por toda tu ayuda!

Ahora también me siento más cómodo con el uso de ese sistema particular (hilo inseguro) en ciertas situaciones.

Publicado el 09/12/2008 a las 23:59
fuente por usuario
En otros idiomas...                            


7 respuestas

votos
7

Cuando llamas a una función, debe hacer lo que esperas que haga con los argumentos que le des. Si llama a una función dos veces exactamente de la misma manera, debe esperar que esa función le proporcione los mismos resultados o haga lo mismo.

Probablemente sea mejor mover esta dependencia de llamada una vez a la lógica que llama a su función muchas veces. Si solo necesita llamar a la función una vez, solo llámela una vez. Alternativamente, pase diferentes argumentos a la función para indicar que está haciendo algo diferente.

Respondida el 10/12/2008 a las 00:17
fuente por usuario

votos
5

Realmente depende precisamente de lo que quieres decir. Si su código será invocado desde más de un hilo, entonces usted tiene una condición de carrera que podría significar que doMyFunctionpodría ser llamado muchas veces. Esto se debe a que más de un hilo podría verificar myStatus, ver que es falso y luego invocar doMyFunction. Puede mejorar la situación un poco estableciendo la variable primero:

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

pero eso solo reduce la ventana de problemas, no la elimina.

Para eliminar la condición de carrera, necesitas un candado.

Respondida el 10/12/2008 a las 00:06
fuente por usuario

votos
4

En C / C ++ generalmente puede mantener el hecho de que doMyFunction () se llama una sola vez encapsulado utilizando una variable estática como esta:

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

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

Esto evita el uso de globales, pero tiene el mismo efecto, y la var estática se declara justo donde es relevante, por lo que está claro lo que está sucediendo. Tenga en cuenta que esto no es seguro para subprocesos, por lo que necesitará un bloqueo si tiene subprocesos.

Respondida el 10/12/2008 a las 00:09
fuente por usuario

votos
2

No es seguro para subprocesos Puede que no le importe, pero dijo "agnóstico del lenguaje": probablemente no desee utilizar este patrón en una biblioteca de propósito general para Java.

Esta es una pregunta difícil de responder de una manera independiente del idioma, porque las alternativas disponibles dependen en gran medida del idioma. Por ejemplo, en POSIX tienes pthread_once si necesitas seguridad de hilos. En C tienes variables locales estáticas para sacar ese booleano del alcance global. En cualquier idioma OO, si está tomando una instantánea de "algo" para su uso posterior, entonces podría haber un objeto adecuado correspondiente al "algo" (o a la instantánea), que podría almacenar el indicador.

Respondida el 10/12/2008 a las 00:09
fuente por usuario

votos
0

En Perl 5.10 o posterior, usaría una statevariable.

use 5.010;

sub test{
  state $once = 1;

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

test for 1..5;

salidas

primero
no primero
no primero
no primero
no primero
Respondida el 10/12/2008 a las 21:01
fuente por usuario

votos
0

No veo otra forma. Lo único que viene a la mente sobre cómo mejorar esto es la seguridad de los hilos. Pero eso solo es necesario si tienes varios hilos llamando a la función.

Respondida el 10/12/2008 a las 00:06
fuente por usuario

votos
0

No veo nada malo con su enfoque aquí. Tenga en cuenta que no siempre es lo "correcto" ... Definitivamente hay cosas equivocadas, pero lo que es correcto puede ser subjetivo y también puede depender drásticamente en función de los requisitos del sistema.

Respondida el 10/12/2008 a las 00:02
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more