scrittura delle funzioni thead
Un thread interno a CLB_thread è definito attraverso tre funzioni, definite usando le macro CLB_lang
- La prima funzione , che è di inizializzazione, è descritta fra le due macro __function_thread_init … __function_end.
- La seconda funzione , che è chiamata a conclusione del thread, è descritta fra le due macro __function_thread_close… __function_end.
- 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 e __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)
