Torna indietro   Hardware Upgrade Forum > Software > Programmazione

HP Elitebook Ultra G1i 14 è il notebook compatto, potente e robusto
HP Elitebook Ultra G1i 14 è il notebook compatto, potente e robusto
Pensato per il professionista sempre in movimento, HP Elitebook Ultra G1i 14 abbina una piattaforma Intel Core Ultra 7 ad una costruzione robusta, riuscendo a mantenere un peso contenuto e una facile trasportabilità. Ottime prestazioni per gli ambiti di produttività personale con un'autonomia lontano dalla presa di corrente che permette di lavorare per tutta la giornata
Microsoft Surface Pro 12 è il 2 in 1 più compatto e silenzioso
Microsoft Surface Pro 12 è il 2 in 1 più compatto e silenzioso
Basato su piattaforma Qualcomm Snapdragon X Plus a 8 core, il nuovo Microsoft Surface Pro 12 è un notebook 2 in 1 molto compatto che punta sulla facilità di trasporto, sulla flessibilità d'uso nelle differenti configurazioni, sul funzionamento senza ventola e sull'ampia autonomia lontano dalla presa di corrente
Recensione REDMAGIC Astra Gaming Tablet: che spettacolo di tablet!
Recensione REDMAGIC Astra Gaming Tablet: che spettacolo di tablet!
Il REDMAGIC Astra Gaming Tablet rappresenta una rivoluzione nel gaming portatile, combinando un display OLED da 9,06 pollici a 165Hz con il potente Snapdragon 8 Elite e un innovativo sistema di raffreddamento Liquid Metal 2.0 in un form factor compatto da 370 grammi. Si posiziona come il tablet gaming più completo della categoria, offrendo un'esperienza di gioco senza compromessi in mobilità.
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 25-02-2010, 22:20   #1
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
[Threading/C++]Idle Wait

Salve,
stavo provando a reinventare un accrocchio per il threading task-based... quindi creo n threads che dovranno poi eseguire i tasks che gli passo.

Però, c'è il problema che i threads ausiliari occupano sempre il 100% del core a loro assegnato, indipendentemente da cosa stanno eseguendo...

Per ora ho risolto mettendo un lock se il thread non ha tasks da eseguire, che lo stoppa, però volevo approfondire la differenza tra il thread "main" e i thread ausiliari...

Se nel thread principale metto solo un if() su qualche valore eseguito in loop, la CPU rimane quasi vuota... mentre negli altri threads schizza al 100%.
è possibile "emulare" questo comportamento negli altri threads?
__________________
*ToMmO*

devlog | twitter
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 00:08   #2
WarDuck
Senior Member
 
L'Avatar di WarDuck
 
Iscritto dal: May 2001
Messaggi: 12814
Ma il thread è messo in un ciclo while(true) con relativo periodo di sleep?

tipo:

Codice:
while(true):
    # fai qualcosa
    sleep(1000) # dorme per un secondo
WarDuck è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 00:13   #3
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Si:

Codice:
	boost::mutex sleepMutex;
	boost::unique_lock<boost::mutex> sleepLock( sleepMutex );
	while(working)
	{
		if( sleeping )
			sleepCondition.wait( sleepLock );

		update();

		this_thread::yield();
	}
Però al posto di sleep uso yield() che dovrebbe rilasciare solo la timeslice in eccesso e non un tempo arbitrario.
Infatti anche se rallentato il sistema è fluido...
__________________
*ToMmO*

devlog | twitter
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 07:19   #4
WarDuck
Senior Member
 
L'Avatar di WarDuck
 
Iscritto dal: May 2001
Messaggi: 12814
Quote:
Originariamente inviato da Tommo Guarda i messaggi
Si:

Codice:
	boost::mutex sleepMutex;
	boost::unique_lock<boost::mutex> sleepLock( sleepMutex );
	while(working)
	{
		if( sleeping )
			sleepCondition.wait( sleepLock );

		update();

		this_thread::yield();
	}
Però al posto di sleep uso yield() che dovrebbe rilasciare solo la timeslice in eccesso e non un tempo arbitrario.
Infatti anche se rallentato il sistema è fluido...
Mmmm non vorrei dire fesserie, cmq con yield comunichi allo scheduler che il tuo thread ha "finito" e quindi di dare la priorità ad altri thread, tuttavia se ce ne sono pochi è probabile che lo scheduler metta in run lo stesso thread (e da qui il 100% della cpu).

Cmq una cosa carina da implementare è un modello che crea thread dinamicamente al bisogno, ovvero solo quando ci sono effettivamente work da effettuare.

Oppure un'altra strategia potrebbe essere quella di crearne un po' e lasciarli dormienti... fai un lock per ogni thread (a cui può accedere solo il master) e sbloccarli solo quando ci sono compiti da effettuare (puoi fare una condition su una variabile puntatore a funzione).

Dovresti anche tenere traccia di quali sono i thread occupati, poiché il master deve saperlo (ed in caso se li trova in gran parte occupati dovrebbe crearne altri).
WarDuck è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 09:53   #5
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
non capisco una cosa... a cosa servono l'if e la yield ?
Sono ridondanti ed inutili se usi il lock.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 10:37   #6
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Quote:
Mmmm non vorrei dire fesserie, cmq con yield comunichi allo scheduler che il tuo thread ha "finito" e quindi di dare la priorità ad altri thread, tuttavia se ce ne sono pochi è probabile che lo scheduler metta in run lo stesso thread (e da qui il 100% della cpu).
Boh yield serve nelle condizioni di "full load", cioè quando effettivamente devo usare più CPU possibile (task assegnato).
Tuttavia lo stesso identico codice nel Main Thread genera un'occupazione del 3 o 4% massimo, evidentemente ha qualche controllo in più?

Il lock serve per spegnere il thread, e l'if è necessario perchè sleepCondition.wait() va chiamato nel thread che deve essere messo ad aspettare, non posso chiamarlo in "sleep()".
Se non metto l'if e il lock non è acquisito crasha.

@WarDuck: è proprio quello che sto facendo... mi creo n "WorkerThreads", dove n = numero_thread_nativi*2 (per qualche motivo sulla mia CPU genera le massime prestazioni)
Questi chiedono dei Tasks ad un Dispatcher che mantiene una queue; se c'è una "Task request miss", cioè non c'è niente da fare, il thread si iberna.
Il Dispatcher poi quando riceve un nuovo Task lo userà per svegliare uno dei thread inattivi invece di metterlo in coda, se possibile.

I thread vengono creati all'inizio dal dispatcher e sono privati, il loro numero non dovrebbe mai variare... e poi l'intero attrezzo serve PROPRIO ad evitare i locks obbligando relazioni di dipendenza tra i tasks... infatti l'unico lock che c'è nel programma sta in "issue" e "request" perchè altrmenti la queue da i numeri

Tornando IT: mi sembra di aver capito che non è ottimale il mio uso dello sleepLock, come faccio a fare un lock "a cui può accedere solo il master"?
__________________
*ToMmO*

devlog | twitter
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 11:51   #7
monelli
Senior Member
 
L'Avatar di monelli
 
Iscritto dal: Feb 2007
Città: Imperia "S.S.28"
Messaggi: 905
Mi intrometto se ti interessa esiste una libreria zthread che permette di fare quello che chiedi te... Puo creare un pool di x thread ed hai una lista di task che vengono mandati in esecuzione su quei thread o accodati...
__________________
Dont drink and drive but smoke and fly
Peugeot 206 enfant terrible!!!
monelli è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 14:52   #8
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
Quote:
Originariamente inviato da Tommo Guarda i messaggi
Boh yield serve nelle condizioni di "full load", cioè quando effettivamente devo usare più CPU possibile (task assegnato).
Tuttavia lo stesso identico codice nel Main Thread genera un'occupazione del 3 o 4% massimo, evidentemente ha qualche controllo in più?

Il lock serve per spegnere il thread, e l'if è necessario perchè sleepCondition.wait() va chiamato nel thread che deve essere messo ad aspettare, non posso chiamarlo in "sleep()".
Se non metto l'if e il lock non è acquisito crasha.

@WarDuck: è proprio quello che sto facendo... mi creo n "WorkerThreads", dove n = numero_thread_nativi*2 (per qualche motivo sulla mia CPU genera le massime prestazioni)
Questi chiedono dei Tasks ad un Dispatcher che mantiene una queue; se c'è una "Task request miss", cioè non c'è niente da fare, il thread si iberna.
Il Dispatcher poi quando riceve un nuovo Task lo userà per svegliare uno dei thread inattivi invece di metterlo in coda, se possibile.
Continuo a non capire... se hai una coda dalla quale prendere i task da eseguire, sara' semplicemente la coda a fare aspettare i thread, a patto di settare le richieste come bloccanti, senza bisogno di if, sleep o wait...
Non ho molta pratica di come usare le boost in questo senso, ma ad esempio sotto unix userei una posix_queue e mi toglierei tutte le rogne.


Quote:
I thread vengono creati all'inizio dal dispatcher e sono privati, il loro numero non dovrebbe mai variare... e poi l'intero attrezzo serve PROPRIO ad evitare i locks obbligando relazioni di dipendenza tra i tasks... infatti l'unico lock che c'è nel programma sta in "issue" e "request" perchè altrmenti la queue da i numeri
come fai ad evitare le dipendenze ? Prima o poi devi verificare se ci sono task disponibili per cui per il lock ci devi passare, non vedo una gran differenza...
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 16:16   #9
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Uhm... per rispondere anche a monelli, sto facendo sta cosa soprattutto per capire il threading, quindi si, molte cose potrebbero non avere alcun senso

Per esempio, che è una "richiesta bloccante"?

Per le dipendenze: un Task è un nodo di un'albero di dipendenze; per cui il Dispatcher percorre questo albero e "stacca" le foglie, che sono i Task pronti per essere eseguiti... in questa maniera se si organizza bene la struttura si riesce a sfruttare un numero arbitrario di cores, indirizzando le foglie allo stesso livello (cioè indipendenti) su thread separati.
Nota: non è che me lo sono inventato, ho copiato spudoratamente Intel Concurrent Collections
Quindi i lock servono solo a task finito, ma non durante come potrebbe essere in un sistema tradizionale con un thread che fa la fisica uno che fa la grafica etc.
E poi ci sono locks e locks... un conto è un lock attivato sempre che blocca tutto un thread aspettando altro; un conto è il lock sulla queue, che ha più una funzione di sicurezza dato che al 99% il programma funge anche senza.
__________________
*ToMmO*

devlog | twitter

Ultima modifica di Tommo : 26-02-2010 alle 16:18.
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 17:10   #10
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
[Parzialmente OT]
@Tommo: dato che mi sembra che stiate parlando di usare dei "working threads" ti posto questo articolo presente nel sito della IBM (il linguaggio di rif. è Java, ma nell'articolo la discussione teorica sui thread pool e le "working" queue è valida a prescindere, e non si fa riferimento a particolari librerie dell'SDK per Java [che all'epoca dell'articolo ancora non esistevano, almeno ufficialmente] ma si basa sulle sole funzionalità di multithreading nude e crude incorporate nel linguaggio).
- Java theory and practice: Thread pools and work queues

Poi, a questa pagina di wikipedia ho visto che ci sono link a zilionate di informazioni.
-> http://en.wikipedia.org/wiki/Thread_pool_pattern
@Edit: compresa la pagina che ti ho linkato sopra
__________________

As long as you are basically literate in programming, you should be able to express any logical relationship you understand.
If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it.
(Chris Crawford)

Ultima modifica di banryu79 : 26-02-2010 alle 17:14.
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 17:39   #11
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
Quote:
Originariamente inviato da Tommo Guarda i messaggi
Uhm... per rispondere anche a monelli, sto facendo sta cosa soprattutto per capire il threading, quindi si, molte cose potrebbero non avere alcun senso

Per esempio, che è una "richiesta bloccante"?
In questo caso, una chiamata alla coda che ritorna solo se ci sono oggetti nella stessa; in caso contrario il thread rimane in attesa che qualche altro thread "spinga" un nuovo oggetto sulla stessa.

Quote:
Per le dipendenze: un Task è un nodo di un'albero di dipendenze; per cui il Dispatcher percorre questo albero e "stacca" le foglie, che sono i Task pronti per essere eseguiti... in questa maniera se si organizza bene la struttura si riesce a sfruttare un numero arbitrario di cores, indirizzando le foglie allo stesso livello (cioè indipendenti) su thread separati.
Nota: non è che me lo sono inventato, ho copiato spudoratamente Intel Concurrent Collections
Quindi i lock servono solo a task finito, ma non durante come potrebbe essere in un sistema tradizionale con un thread che fa la fisica uno che fa la grafica etc.
E poi ci sono locks e locks... un conto è un lock attivato sempre che blocca tutto un thread aspettando altro; un conto è il lock sulla queue, che ha più una funzione di sicurezza dato che al 99% il programma funge anche senza.
I lock li intendevo sulla sola coda di task e servono solo per sincronizzare l'accesso alla coda. A seconda dei casi l'accesso lo devi gestire tu, oppure puo' essere parte delle API della coda (ade sempio come e' nel caso delle code messaggi POSIX).

Io una buona implementazione della tua idea la vedrei nel seguente modo:

- Utilizzi due code. Una coda di task da fare e una di task fatti. Il thread principale legge i task fatti e mette i task da fare. I thread worker leggono dalla coda dei task da fare e spingono indietro quelli fatti

- Il thread principale procede come segue:
Codice:
* fa una prima scansione dell'albero : spingi ogni foglia "libera" sullla coda dei task da fare
* Mettiti in ascolto sulla coda dei task fatti. Per ogni task che arriva verifica il padre del task. Se il padre ha tutti i figli completati, allora spingi tale nodo sui task da fare
Mentre gli altri thread procedono semplicemente come
Codice:
* mettiti in ascolto sulla coda dei task. Quando arriva un task eseguilo, una volta finito rimettilo sull'altra coda
Poi dipende da come costruisci/mantieni/aggiorni l'albero, ma come idea di base dovrebbe essere semplice da codificare, e anche sufficientemente performante.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 18:47   #12
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
La condition non avrebbe bisogno di avere una mutex acquisita ?
Codice:
	boost::mutex sleepMutex;
	boost::unique_lock<boost::mutex> sleepLock( sleepMutex );
	while(working)
	{
		sleepLock.lock();
		if( sleeping )
			sleepCondition.wait( sleepLock );
		sleepLock.unlock();

		update();

		this_thread::yield();
	}
PS: non conosco libboost, ma vado per analogia con pthread

Ultima modifica di cionci : 26-02-2010 alle 20:03.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 26-02-2010, 19:44   #13
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Io sinceramente farei tutto senza condition...una coda circolare con i thread in attesa, una mutex per ogni elemento della coda. Quando un thread è disponibile acquisisce un elemento della coda, la relativa mutex e scrive i risultati in un'apposita struttura (ad esempio allocando una opportuna struttura dati).
Il thread principale si occupa di recuperare i risultati e poi fa una signal sulla mutex.

La struttura della coda può essere quella classica, con semaforo pieno e semaforo vuoto.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 27-02-2010, 10:42   #14
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Grazie per le idee, mi sa che qua ci sta un bel refactoring
La coda dei task finiti in realtà non mi è sembrata troppo utile, perchè richiede un lock in più quando ci si va a scrivere, e poi un altro thread che volesse trovarci dentro un task a cui è interessato dovrebbe leggersela tutta.
Invece io ho messo uno stato interno di Task (completed, etc), un Listener, e un Garbage Collector per i Tasks: cioè se si assegna un listener ad un task, quando termina questo aggiunge un evento "listenedTaskCompleted" su una queue di Dispatcher, quindi dispatcher provvede a chiamare il Listener quando ci si trova sul main thread.
Quindi (se il thread è "autoDeletable"), percorre l'albero a partire dal Task completato e distrugge quello e tutti i parents diventati inutili col completamento del Task corrente (es: erano aspettati solo da lui).

Comunque il problema principale è che la documentazione di Boost fa un pò pena, è difficile capire come fungono mutex eccetera.

@cionci: mi sembra che lock e unlock li gestisce wait, nel senso che quando ci entra chiama unlock() + lock() e quando esce chiama lock() + unlock() se possibile.
__________________
*ToMmO*

devlog | twitter
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 27-02-2010, 10:47   #15
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Quote:
Originariamente inviato da Tommo Guarda i messaggi
@cionci: mi sembra che lock e unlock li gestisce wait, nel senso che quando ci entra chiama unlock() + lock() e quando esce chiama lock() + unlock() se possibile.
No, altrimenti non può gestire la concorrenza sulla condizione.
Solitamente la condition si chiama per attendere che si verifichi una determinata condizione. Questa condizione viene testata tramite variabili condivise, è chiaro che queste variabili condivise debbano essere gestite in mutua esclusione. Inoltre se guardi la documentazione vedrai che genera un'eccezione se il lock non è acquisito.
Se acquisisse il lock dentro la wait la mutua esclusione sulla condizione non sarebbe garantita. Ci potrebbero essere tra l'altro delle corse critiche.

Ultima modifica di cionci : 27-02-2010 alle 10:59.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 27-02-2010, 15:27   #16
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
Quote:
Originariamente inviato da Tommo Guarda i messaggi
Grazie per le idee, mi sa che qua ci sta un bel refactoring
La coda dei task finiti in realtà non mi è sembrata troppo utile, perchè richiede un lock in più quando ci si va a scrivere, e poi un altro thread che volesse trovarci dentro un task a cui è interessato dovrebbe leggersela tutta.
Invece io ho messo uno stato interno di Task (completed, etc), un Listener, e un Garbage Collector per i Tasks: cioè se si assegna un listener ad un task, quando termina questo aggiunge un evento "listenedTaskCompleted" su una queue di Dispatcher, quindi dispatcher provvede a chiamare il Listener quando ci si trova sul main thread.
Uhm, la coda è poco utile perchè la puoi sostituire con tre-quattro oggetti differenti ? . Tieni presente che parlavo di coda di task, ma all'atto pratico la puoi benissimo (anzi meglio) implementare come coda di numeri (task id).

Quote:
Quindi (se il thread è "autoDeletable"), percorre l'albero a partire dal Task completato e distrugge quello e tutti i parents diventati inutili col completamento del Task corrente (es: erano aspettati solo da lui).
È quello che fa la mia soluzione con una differenza sostanziale. Cosa succede quando due listener finiscono contemporaneamente si mettono a modificare l'albero contemporaneamente. In bocca al lupo.
Puoi sistemare facilmente... riempiendo di lock l'albero ( o anche uno solo che blocchi tutto ).
Peggio ancora. Se la callback viene eseguita all'atto della conclusione del task, per come l'hai descritto verra' eseguita dal thread stesso. Il che vuol dire che tutti i processori della tua macchina dovrano costantemente sincronizzare la loro cache devastando le prestazioni.
Idealmente vuoi che le informazioni condivise tra i vari thread siano il minimo possibile. Se riesci a far stare l'albero sulla cache di un solo processore è molto meglio, tanto non ti serve per eseguire i singoli task. E l'implementazione, ripeto, è veramente semplcie.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 27-02-2010, 15:58   #17
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Non avevo letto molto bene la struttura che vuoi realizzare. Comunque la concorrenza secondo me può essere gestita sui risultati, non sulla struttura dei thread. I thread dovrebbero essere gestiti separatamente.

Dato un albero di dipendenza il dispatcher si occupa solo di allocare il o i thread che dipendono da tutti gli altri.
C'è un canale di comunicazione fra i thread. Un thread che dipende da un altro si registra sul canale inviando i dati da elaborare e si mette in attesa dei risultati. Quando l'elaborazione di un thread finisce questo invia i risultati sul canale di comunicazione e si mette in attesa di ricevere nuovi dati su cui lavorare.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 28-02-2010, 01:08   #18
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Quote:
Originariamente inviato da marco.r Guarda i messaggi
Uhm, la coda è poco utile perchè la puoi sostituire con tre-quattro oggetti differenti ? . Tieni presente che parlavo di coda di task, ma all'atto pratico la puoi benissimo (anzi meglio) implementare come coda di numeri (task id).
Beh la mia implementazione fa anche altro, visto che si prende la briga di chiamare una funzione dell'User nel main thread per poi cancellare da solo il Task...
quello che intendevo con "poco utile" è che con una semplice completed queue hai che il main thread si deve prendere la briga di verificare da sè lo stato di completamento, quindi andarsi a cercare il task in oggetto tra i completi e toglierlo.
Nè comodo nè efficiente

Quote:
Originariamente inviato da marco.r Guarda i messaggi
È quello che fa la mia soluzione con una differenza sostanziale. Cosa succede quando due listener finiscono contemporaneamente si mettono a modificare l'albero contemporaneamente. In bocca al lupo.
Puoi sistemare facilmente... riempiendo di lock l'albero ( o anche uno solo che blocchi tutto ).
Peggio ancora. Se la callback viene eseguita all'atto della conclusione del task, per come l'hai descritto verra' eseguita dal thread stesso. Il che vuol dire che tutti i processori della tua macchina dovrano costantemente sincronizzare la loro cache devastando le prestazioni.
Idealmente vuoi che le informazioni condivise tra i vari thread siano il minimo possibile. Se riesci a far stare l'albero sulla cache di un solo processore è molto meglio, tanto non ti serve per eseguire i singoli task. E l'implementazione, ripeto, è veramente semplcie.
Allora, i listener sono assolutamente read-only e vengono chiamati SOLO sul main thread.
Il lock serve solo quando il WorkerThread notifica il Dispatcher che un Task Listened (non lo sono tutti, anzi, dovrebbero essere uno o due) è completato.
Questo fa si che il Task sia considerato automaticamente NON deletable, ma viene cancellato solo dal main thread alla fine della chiamata al listener se permane in stato "autoDeletable".

Però non c'entra niente, ma il problema dell'albero in effetti esiste... dato che tutti i Task eccetto quelli listened vengono eliminati sul thread di appartenenza... mi sa che in effetti a sto punto va unificata la cosa con una completed queue

Quote:
Originariamente inviato da cionci Guarda i messaggi
Non avevo letto molto bene la struttura che vuoi realizzare. Comunque la concorrenza secondo me può essere gestita sui risultati, non sulla struttura dei thread. I thread dovrebbero essere gestiti separatamente.

Dato un albero di dipendenza il dispatcher si occupa solo di allocare il o i thread che dipendono da tutti gli altri.
C'è un canale di comunicazione fra i thread. Un thread che dipende da un altro si registra sul canale inviando i dati da elaborare e si mette in attesa dei risultati. Quando l'elaborazione di un thread finisce questo invia i risultati sul canale di comunicazione e si mette in attesa di ricevere nuovi dati su cui lavorare.
Ma, quello che proponi te a "canali di comunicazione" sembra l'approccio vecchio che NON volevo seguire, con 2 threads in continue race conditions tra di loro...
nel mio design si allocano n thread (con n sconosciuto all'utente, e con i thread classe privata di Dispatcher) e viene esposta solo l'interfaccia "ad albero" dei Task.
La dipendenza è resa semplicemente dalle relazioni tra questi ultimi, e i thread sono faccenda del dispatcher...
Un task dovrebbe essere completamente data parallel, cioè deve eseguirsi dall'inizio alla fine senza alcuna richiesta verso threads di livello uguale o superiore al suo, per definizione

Comunque, non pensavo di doverlo mai chiedere in questi termini ma avete un buon testo di riferimento da studiare?
Il threading mi sembra proprio difficile da afferrare per prove...
PS: preferibilmente roba gratis
__________________
*ToMmO*

devlog | twitter
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 28-02-2010, 01:32   #19
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Quote:
Originariamente inviato da Tommo Guarda i messaggi
Ma, quello che proponi te a "canali di comunicazione" sembra l'approccio vecchio che NON volevo seguire, con 2 threads in continue race conditions tra di loro...
Non necessariamente. Dipende da come implementi il canale e i thread
Ad esempio puoi implementare con due stati:
- registrazione richieste sul canale
- elaborazione e invio risultati sul canale
I due stati possono anche non necessariamente essere lo stesso thread
Il canale può anche essere il dispatcher stesso.

Alloco il thread A, nel costruttore si registra sul canale per un thread di tipo B e due thread di tipo C. Termina il costruttore.

Il canale vedendo le richieste alloca i thread richiesti. Il thread di tipo B richiede l'esecuzione di un thread del tipo D. Il canale alloca un thread di tipo D. Il thread di tipo D non registra alcuna richiesta, quindi i requisiti sono soddisfatti e il canale "invia i risultati" (fra virgolette perché di fatto mette in esecuzione il thread).
Alla fine di D, D invia i risultati sul canale, il canale verifica che i requisiti del thread B sono soddisfatti...invia i risultati ed esegue il thread B.
L'unico che cicla è il thread del canale. Volendo si potrebbe lavorare anche su questo aspetto.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 28-02-2010, 16:49   #20
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
Quote:
Originariamente inviato da Tommo Guarda i messaggi
Beh la mia implementazione fa anche altro, visto che si prende la briga di chiamare una funzione dell'User nel main thread per poi cancellare da solo il Task...
quello che intendevo con "poco utile" è che con una semplice completed queue hai che il main thread si deve prendere la briga di verificare da sè lo stato di completamento, quindi andarsi a cercare il task in oggetto tra i completi e toglierlo.
Nè comodo nè efficiente
Dipende come implementi l'albero. saranno 20 linee di codice che lavorano in tempo costante.
Se ci dai un esempio di come dovrebbero essere le api si puo' provare una implementazione rapida, cosi' possiamo confrontare le varie idee.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele
marco.r è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


HP Elitebook Ultra G1i 14 è il notebook compatto, potente e robusto HP Elitebook Ultra G1i 14 è il notebook c...
Microsoft Surface Pro 12 è il 2 in 1 più compatto e silenzioso Microsoft Surface Pro 12 è il 2 in 1 pi&u...
Recensione REDMAGIC Astra Gaming Tablet: che spettacolo di tablet! Recensione REDMAGIC Astra Gaming Tablet: che spe...
Dopo un mese, e 50 foto, cosa abbiamo capito della nuova Nintendo Switch 2 Dopo un mese, e 50 foto, cosa abbiamo capito del...
Gigabyte Aero X16 Copilot+ PC: tanta potenza non solo per l'IA Gigabyte Aero X16 Copilot+ PC: tanta potenza non...
Finalmente rilevata la stella compagna d...
UBTech Walker S2: il robot umanoide cine...
Musk guarda ai più piccoli: in ar...
The Witcher 3 su RISC-V? Ora è po...
Il segreto per lavorare meglio? È...
Mini PC con 16GB RAM e 512GB SSD a poco ...
Radeon RX 9000: questa app gratuita cons...
Windows 11 supporterà la condivis...
Synology DS725+: connettività 2.5...
Microsoft vuole dire addio ai problemi d...
I giocatori si divertono a spendere di p...
Il monopattino che punta a battere il re...
Apple e crittografia, Londra verso la re...
Trump pubblica video con Obama arrestato...
A Vienna consegne postali completamente ...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 23:10.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v