Dichiarazione di un thread

$_thread(func_name, p1,..,pn)

La macro è equivalente alla classe  std::thread e corrisponde al lancio di una funzione thread, func_name, al quale vengono passati i parametri  p1,p2.. pn: di seguito è riportato un esempio:

bool CLB_disk_mapper::Put_seq_lines(void *buf, int nlines)
{
		__getstr
		$_lock(_$str->mut)

		size_t bsz = nlines * _$str->lsize;
		if (!_$str->tbuf)
		{
			_$str->tbuf = (UBYTE *)malloc(bsz);
			_$str->tbuf_size = bsz;
		}
		else {
			if (_$str->tbuf_size < bsz)
			{
				_$str->tbuf = (UBYTE *)realloc(_$str->tbuf,bsz);
				_$str->tbuf_size = bsz;
				_$str->tbuf_bytes = bsz;
			}
		}
		if (!_$str->tbuf) return false;
		_$str->tbuf_bytes = bsz;
		memcpy(_$str->tbuf, buf, bsz);

		$_thread t(_thread_transfer_to_disk, _$str,nlines);
		t.detach();

		return true; // return (_$str->file.Write(buf, nlines*_$str->lsize) != -1);
}

CLB_disk_mapper è una classe  che mappa un’immagine su disco, in un file temporaneo, permettendo l’accesso trasparente a parti in memoria ed altre residenti su file. Il programmatore non si preoccupa di sapere quale parte è su disco, poiché l’immagine è comunque completamente accessibile attraverso funzioni di estrazione/scrittura di pixel o blocchi di linee.

la funzione CLB_disk_mapper::Put_seq_lines(void *buf, int nlines) viene richiamata per trasferire su disco un blocco di righe, utilizzando un thread, ed occorrerà fare in modo che la funzione, chiamata più volte, non generi errori di scrittura, non avendo terminato uno dei thread. All’ingresso della funzione è usata la macro

	$_lock(_$str->mut)

la quale rimane in attesa che  il mutex  _$str->mut venga sbloccato. Quando si verifica questa condizione, prosegue eseguendo alcune istruzioni preparatorie e lanciando una funzione come thread

	$_thread t(_thread_transfer_to_disk, _$str,nlines);
	t.detach();

La prima riga dichiara un thread t che esegue la funzione  _thread_transfer_to_disk, passandogli i due parametri richiesti; quindi rilascia il thread t (che quindi continuerà l’esecuzione in modo autonomo) ritornando true;

Chiamando più volte la funzione Put_seq_lines, questa rimarrà in attesa che il mutex _$str->mut venga sbloccato, prima di generare il thread di scrittura su disco.

Analizziamo ora la scrittura della funzione lanciata come thread:

void _thread_transfer_to_disk(CLASS_STR, int nlines)
{
	$_lock(_$str->mut)
	UBYTE *buf = _$str->tbuf;
	for (int i=0;i<nlines;i++,buf+=_$str->lsize)
	  _$str->file.Write(buf, _$str->lsize);
}

Osserviamo che la prima istruzione è ancora una volta $_lock(_$str->mut), che ha esattamente la stessa funzione della chiamata in CLB_disk_mapper::Put_seq_lines.

Superata la barriera di blocco, viene eseguito un ciclo di trasferimento delle informazioni su disco, quindi termina il thread;

Per chiarire meglio l’uso della macro $_lock, dobbiamo fare alcune precisazioni osservando la sua definizione:

#define  $_lock(_mutex) std::lock_guard<std::mutex> lk (_mutex);

la macro crea una classe lock_guard alla quale viene assegnato il mutex;

La classe lock_guard è un wrapper che fornisce un comodo meccanismo in stile RAII per gestire un mutex in un blocco di codice (nel nostro caso tutta la funzione).

La classe lock_guard non è copiabile.

Quando viene creato un oggetto lock_guard, questi tenta di diventare proprietario del mutex assegnatogli,  attendendo che lo stesso venga sbloccato da chi ne ha il controllo; quindi, a sua volta blocca il mutex, fino al rilascio dell’istanza  lock_guard all’uscita del blocco di definizione (la funzione stessa od un blocco di codice {…} nel quale è dichiarato).

Pages: 1 2 3 4
Skip to toolbar