Programmed_action: azioni programmate nell’applicazione

Di cosa stiamo parlando?

Capita con frequenza di dovere allocare particolari oggetti (classi, strutture ecc) la cui vita perdura fino alla chiusura dell’applicazione; in questi casi a fine applicazione occorrerà distruggere gli oggetti, per non generare perdita di memoria (i famigerati memory leaks..)

Capita anche di dovere programmare delle attività nel software che devono essere tempificate (ad esempio effettuare un back-up di file utilizzati ogni x giorni, oppure salvare un documento in un’area temporanea ogni 5 minuti ecc..)

In questi casi, come in innumerevoli altre situazioni, è utile avere a disposizione un’infrastruttura che permette questi automatismi e, in questi casi, è utile usare la classe Programmed_action.

Nelle API di Colibrì le azioni programmate sono funzioni richiamate in condizioni particolari dal framework dell’applicazione; si suddividono in tre tipologie:

  • on_start_action : azioni eseguite allo start dell’applicazione
  • on_end_action : azioni eseguite a chiusura del programma
  • on_time_action: azioni eseguite in continuo a tempi prefissati  (minimo 1 secondo)

L’ordine di esecuzione delle on_start_action e delle on_end_action è quello della loro dichiarazione.

Le azioni programmate sono definite mediante la classe  Programmed_action che appartiene al namespace ACTIONS.

la callback prg_action

Un’azione programmata è definita attraverso una callback di tipo prg_action che riceve in ingresso un parametro e rimanda un altro parametro generico, che sostituisce il precedente; il parametro della prg_action può essere 0 e può rimandare 0; inoltre il gestore delle Programmed_action, completamente agnostico rispetto al significato dell’azione ed al tipo di dati del parametro,  conserva un contatore del numero di chiamate eseguite;  i tipi prog_mode  nel frammento di codice definiscono le modalità d’uso della Programmed_action .

typedef  void *  (*prg_action)(void *params);

typedef enum prog_mode {
    on_start_action = 0,
    on_end_action,
    on_time_action,
} prog_mode;

Struttura della classe

La classe espone 3 funzioni statiche,; la prima Add_action(), viene utilizzata per attivare una Programmed_action; la seconda, Get_status() rimanda il numero di volte che è stata richiamata la call_back.

L’ultima funzione,   Close(), è usata dal framework di Colibri per eseguire le call_back programmate come on_end_action, a chiusura dell’applicazione

class AFX_EXT_CLASS  Programmed_action
	{
	public:
		Programmed_action();
		~Programmed_action();

		static int Add_action(prg_action call_back, void *params, prog_mode mode, int h = 0, int m = 0, int s = 0);
		static int Get_status(int action_handler);

		static bool Close();

	}

Add_action()

La funzione riceve i seguenti parametri:

  • la call_back definita
  • params puntatore a parametri iniziali
  • mode tipologia di azione
  • h,m,s tempo in ore,minuti e secondi nel caso mode==on_time_action (non ha  nessun significato altrimenti)

Add_action restituisce un handle alla funzione attivata che corrisponde ad un numero progressivo nella lista delle funzioni attive; l’handle può essere usato in seguito per interrogare lo stato della Programmed_action attivata (vedere la Get_status()).

Get_status()

rimanda lo stato dell’istanza attivata mediante la Add_action, cioè  il numero di volte che è stata richiamata la call_back associata;

Come attivare  una Programmed_action

Di seguito si riporta un frammento di codice che attiva un’azione programmata per essere eseguita a chiusura dell’applicazione: il frammento è quello di una funzione interna alla classe TAG:

	__programmed_action(_destroy_list, LIST, par)
	{
		TAG::Destroy_registered_tags();
	}
	__end_programmed_action


	static TAG *_get_regs(STRING id)
	{
		if (!_registered_tags)
		{
			LIST_INIT(_registered_tags, TAG)
			__start_programmed_action(_destroy_list, _registered_tags, on_end_action, 0,0,0)
		}
		__for_each_object($_registered_tags, TAG)
				if (STR_EQUAL(EL->Get_id(), id))
					return EL;
			__next_object
			return 0;
	}

	bool TAG::Register_tag()
	{
		if (!_get_regs(this->Get_id()))
		{
			TAG *tg = this->New();
			LIST_Push($_registered_tags, tg)
			return true;
		}
		return false;
	}

 

la funzione _get_regs è statica al file TAG.cpp; non è importante comprenderne l’uso, ma ne diamo una descrizione sommaria: se la LIST _registered_tags non è allocata, la alloca (LIST_INIT..) e programma una funzione da richiamare a chiusura dell’applicazione ( __start_programmed_action(_destroy_list, _registered_tags, on_end_action, 0,0,0) ). La funzione è definita nel blocco _programmed_action {..} _end_programmed_action che è la funzione di call_back definita mediante due macro; La call_back _destroy_list così definita ha il compito di distruggere la lista precedentemente allocata a chiusura dell’applicazione; 

Di seguito si riportano le definizioni delle macro utilizzate in questo esempio e contenute nel file “Programmed_action.h”:

#define  __programmed_action( prog_name, type, par)  void *prog_name( void *_pp) { type *par=(type *)_pp ;   

#define	 __end_programmed_action return 0; }

#define __start_programmed_action( call_back, params, mode, h,m,s)   { ACTIONS::Programmed_action::Add_action(call_back, params, ACTIONS::mode, h,m,s);}

Dall’analisi del costrutto delle macro si dedurrà il loro significato; è importante ricordare che la call_back può ricevere un puntatore a parametri il cui tipo è noto all’interno del file dove è definita la call_back; quando viene chiamata, la call_back (nell’esempio dato la funzione _destroy_list) può utilizzare il puntatore ricevuto (notare che nella macro __programmed_action si procede alla sua tipizzazione..), ma può ritornare un nuovo puntatore, oppure ritornare il valore 0; il valore restituito sarà ricevuto alla prossima call_back; per ricevere la volta successiva un valore 0 basta non restituire niente (analizza la macro __end_programmed_action per comprendere perché..)

Leave a Reply

Skip to toolbar