scrittura delle funzioni thead

Un thread interno a CLB_thread è definito attraverso tre funzioni, definite  usando le macro CLB_lang

  1. La prima funzione , che è di inizializzazione, è descritta fra le due macro __function_thread_init …  __function_end.
  2. La seconda funzione , che è chiamata a conclusione del thread, è descritta fra le due macro __function_thread_close…  __function_end.
  3. La terza funzione, il thread da eseguire, è scritta nel blocco  __thread_function(calc_dither)  …  __thread_end.

I comandi macro nascondono tutta la complessità di controllo degli eventi connessa alla gestione del thread, quali le semaforizzazioni, la risposta egli eventi standard (sospensione, stop, continuazione) lanciati dall’esterno, o di attesa di eventi dall’interno (waiting di eventi esterni..). Sono uno strumento per standardizzare i controlli del processo gestito dal thread,

Il codice, relativo alla classe THREAD_calc_dither usata come esempio è sotto riportato.

/** funzione che prepara i dati del thread 
*/
__function_thread_init

__function_end

/** disalloca i dati non più necessari allocati nel thread..
*/
__function_thread_close

__function_end

__thread_function(calc_dither)
				
	__thr_pop_p(ichn,IMCHN)			// canale da retinare
	__thr_pop_p(dth,DITHER)			// modello di dithering usato
	__thr_pop_p(dx,int)				// dimensioni mappa generata
	__thr_pop_p(dy,int)
	__thr_pop_p(_DENSITY,CURVE);		// curva di correzione densità

	int siz=1;

	if (!IBF.OpenTempFile(*dx,*dy,siz))
		EXIT_TASK

	DOC_AREA *sz=ichn->channel.GetSize();

	// scala da applicare
	double scy=(double)sz->dy/(double)*dy;
	double scx=(double)sz->dx/(double)*dx;

	__$btm_Open((&(ichn->channel)))

	dth->StartFiltering();

	UBYTE *src=new UBYTE[*dx];	// linea da scalare
	_$str->src = src;

	int npts = 0;

	// tabella densità calcolata
	if (_DENSITY)
	{
		_$str->_dens = _DENSITY->Get_points(&npts);
		if (npts != 101)
		{
			__trace(L"numero di punti curva densità sbagliato!")
		}
	}

	{

		for (int y = 0; y < *dy; y++) 
               {
    		      if (!(y % 100)) 
                     {
		        __test_thread_status
			__thr_sig_perc(((float)y*100.0f) / (float)*dy)
		     }
		     UBYTE *buf = BPIX(_BMAN, 0, (int)(scy*y));	// legge la linea sorgente UBYTE

#define _DENS(v) _$str->_dens[v].Y

                        // scalatura della linea originale;
			if (_DENSITY) {
				for (int x = 0; x < *dx; x++)
					src[x] = (UBYTE)(2.55f*(float)_DENS(buf[(int)(scx*x)]));
			}
			else
				for (int x = 0; x < *dx; x++)
					src[x] = (UBYTE)(2.55f*(float)buf[(int)(scx*x)]);

			UBYTE *map = IBF.GetLine(y, true);
			dth->Filter(map, src, *dx);
		}
		ichn->channel.FlushToFile();		// rilascia nuovamente il canale su file temporaneo
		__thr_sig_perc(100.0f);
	}
__thread_end  


Nel caso in discussione le funzioni di inizializzazione (__function_thread_init) e terminazione (__function_thread_close) , chiamate automaticamente dall’interno del thread attraverso i comandi CLB_lang,  sono completamente vuote, non avendo compiti da svolgere  ( ad esempio avrebbe potuto allocare o disallocare dati usati nel thread main..)

__thread_function( calc_dither )  { ….. } __thread_end 

Il blocco definisce il thread  di nome calc_thread eseguito mediante il comando  __thread_exec(calc_dither)  dalla funzione Start(). Si possono osservare un insieme di macro CLB_lang che svolgono diverse funzioni:

__thr_pop_p(ptr,type)

estrae uno dei parametri passati atttraverso la __thr_push_p in fase di allocazione del thread: ptr è il nome di un puntatore di tipo type inizializzato mediante questa macro.

La macro è richiamata più volte per  ricevere, nell’ordine di immissione, tutti i parametri passati alla classe mediante CLB_thread::Set_argument_list(..) o la sequenza di comandi __thr_push_p.

Il corpo della funzione contiene le istruzioni necessarie al compito assegnato, ma non sono argomento di questo articolo. Vengono invece discusse alcune macro di CLB_lang usate nel ciclo di esecuzione: __test_thread_status  e __thr_sig_perc.

__test_thread_status 

è un comando macro estremamente importante, che ha il compito di analizzare lo stato del thread ed eventualmente compiere i passaggi associati. osserviamone la definizione:

#define __test_thread_status { __test_thread_paused __test_thread_exit }

la macro esegue in sequenza due altre macro __test_thread_paused  e __test_thread_exit ,  così definite:

__test_thread_paused

#define __test_thread_paused 		if (__event_verified(EV_PAUSE_THR)) { __event_set( EV_PAUSEED_THR) __event_wait(EV_CONTINUE_THR); }

La macro verifica che sia verificato l’evento EV_PAUSE_THR (attivato da qualcuno all’esterno o all’interno del thread  chiamando la funzione CLB_thread::Suspend() ) e, se si, assegna un flag ed attende che sia verificato l’evento EV_CONTINUE_THR (macro __event_wait(..)). fino a quel  momento il thread rimane in uno stato di attesa.   L’evento EV_CONTINUE_THR  è alzato dall’esterno attraverso  la CLB_thread::Continue() .

__thr_sig_perc(perc)

La macro segnala al gestore dei thread quale è la percentuale del ciclo attualmente eseguita. La segnalazione è usata da un thread (CLB_thread_list) per visualizzare lo stato del thread specifico, o dell’insieme dei thread figli.  Se non è attivo un thread di cattura della percentuale, non succede niente.

notare che  le macro  __test_thread_status __thr_sig_perc  sono state inserite  in  un blocco che viene eseguito ogni cento linee analizzate: la scelta fatta dal programmatore è stata di non eseguire il test con frequenza eccessiva, considerando sufficiente quella scelta..

.....
		for (int y = 0; y < *dy; y++) 
               {
    		      if (!(y % 100)) 
                     {
		        __test_thread_status
			__thr_sig_perc(((float)y*100.0f) / (float)*dy)
		     }
.....
.....
.....

E’ importante osservare che non è obbligatorio inserire queste macro nel codice; Se non presenti, il thread don potrà essere interrotto dall’esterno (__test_thread_paused) o non fornirà informazioni sul suo stato di esecuzione (__thr_sig_perc)

 

Pages: 1 2 3 4 5 6 7 8
Skip to toolbar