Torna indietro   Hardware Upgrade Forum > Software > Programmazione

WoW: Midnight, Blizzard mette il primo, storico mattone per l'housing e molto altro
WoW: Midnight, Blizzard mette il primo, storico mattone per l'housing e molto altro
Con Midnight, Blizzard tenta il colpaccio: il player housing sbarca finalmente su Azeroth insieme a una Quel'Thalas ricostruita da zero. Tra il dramma della famiglia Ventolesto e il nuovo Prey System, ecco com'è la nuova espansione di World of Warcraft
Ecovacs Goat O1200 LiDAR Pro: la prova del robot tagliaerba con tagliabordi integrato
Ecovacs Goat O1200 LiDAR Pro: la prova del robot tagliaerba con tagliabordi integrato
Nuova frontiera per i robot tagliaerba, con Ecovacs GOAT O1200 LiDAR Pro che riconosce l'ambiente in maniera perfetta, grazie a due sensori LiDAR, e dopo la falciatura può anche rifinire il bordo con il tagliabordi a filo integrato
Recensione Samsung Galaxy S26+: sfida l'Ultra, ma ha senso di esistere?
Recensione Samsung Galaxy S26+: sfida l'Ultra, ma ha senso di esistere?
Equilibrio e potenza definiscono il Samsung Galaxy S26+, un flagship che sfida la variante Ultra e la fascia alta del mercato con il primo processore mobile a 2nm. Pur mantenendo l'hardware fotografico precedente, lo smartphone brilla per un display QHD+ da 6,7 pollici d'eccellenza, privo però del trattamento antiriflesso dell'Ultra, e per prestazioni molto elevate. Completano il quadro la ricarica wireless a 20W e, soprattutto, un supporto software settennale
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 19-10-2009, 09:56   #1
alex783
Senior Member
 
Iscritto dal: Jan 2009
Messaggi: 609
[C#] Gestione dei thread all'interno di un ciclo di "for"

Ciao a tutti! sto avendo un problema a gestire i thread all'interno di un ciclo di "for".

Mi spiego: il mio obiettivo è di avviare un metodo ogni qualvolta il ciclo di "for" avanza di uno step. Però, per evitare che il metodo blocchi l'esecuzione del programma, avevo pensato di avviarlo in un thread separato. In questo modo, ad ogni ciclo di "for" viene creato un thread che avvia il proprio metodo.

Però non funziona come vorrei e non sto capendo il perché.
Pubblico il codice perché mi possiate aiutare, se potete. Grazie.

Codice:
public partial class MyForm: Form
{
private ArrayList listOfThreads = new ArrayList(); int i=0; int a = 0;
public MyForm() {
InitializeComponent(); for (i = 0; i < 3; i++) {
this.listOfThreads.Add(new Thread(delegate() {
MessageBox.Show("'i' corrente vale: "+i.ToString()); mio_metodo(i);
})); ((Thread)this.listOfThreads[i]).SetApartmentState(ApartmentState.STA); ((Thread)this.listOfThreads[i]).Start();
}
}
}
In sostanza, anziché mostrarmi tre finestre di dialogo "'i' vale: 0", "'i' vale: 1", "'i' vale: 2" e, dopo ognuna delle quali, eseguire il metodo mio_metodo(i) passandogli il valore di "i" corrente, mi mostra due finstre "'i' vale: 2" e una finestra "'i' vale: 3" (come fa "i" a raggiungere il valore "3" se il limite al ciclo di "for" è "2"? ) e mi esegue tre volte il metodo mio_metodo(i) con "i" sempre pari a "3"


HELP, Please!

Thanks so much!
__________________
L'iPad? Potrebbe esserci gente che, pur d'avere il nuovo gadget, si mette a leggere i libri. Questa sì sarebbe una rivoluzione (Beppe Severgnini)
alex783 è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 11:51   #2
||ElChE||88
Senior Member
 
Iscritto dal: Dec 2003
Messaggi: 4907
È un problema di sincronizzazione.
La variabile i viene incrementata dal ciclo for contemporaneamente all'esecuzione dei vari thread.
Puoi risolvere passando la variabile come argomento ad un metodo (anonimo e non) in modo da crearne una copia.

PS: Usa le collezioni generiche, evita ArrayList come la peste.
||ElChE||88 è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 21:07   #3
MarcoGG
Senior Member
 
L'Avatar di MarcoGG
 
Iscritto dal: Dec 2004
Messaggi: 3210
Quote:
Originariamente inviato da alex783 Guarda i messaggi
il mio obiettivo è di avviare un metodo ogni qualvolta il ciclo di "for" avanza di uno step. Però, per evitare che il metodo blocchi l'esecuzione del programma, avevo pensato di avviarlo in un thread separato. In questo modo, ad ogni ciclo di "for" viene creato un thread che avvia il proprio metodo.
...
...
(come fa "i" a raggiungere il valore "3" se il limite al ciclo di "for" è "2"? )
Vero. Succede qualcosa di veramente strano. Me lo chiedo anch'io, com'è possibile che i arrivi a 3 ?!

Cmq, la risolverei così :

Codice:
        private ArrayList listOfThreads = new ArrayList();

        private void mio_metodo(object I) 
        {
            MessageBox.Show("'i' corrente vale: " + I.ToString());
            //...
        }
Codice:
            for (int i = 0; i < 3; i++)
            {
                Thread T = new Thread(new ParameterizedThreadStart(mio_metodo)); 
                T.SetApartmentState(ApartmentState.STA);
                this.listOfThreads.Add(T);
                T.Start(i);
            }
MarcoGG è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 21:12   #4
alex783
Senior Member
 
Iscritto dal: Jan 2009
Messaggi: 609
@||ElChE||88: in parte ho risolto... come hai detto tu...

P.S: perché dovrei evitare le ArrayList? le ho sempre usate, mai un problema, e le trovo molto comode


EDIT:
@MarcoGG: uhm... ho visto or ora il tuo intervento, ti ringrazio. Ora provo subito la tua soluzione.
__________________
L'iPad? Potrebbe esserci gente che, pur d'avere il nuovo gadget, si mette a leggere i libri. Questa sì sarebbe una rivoluzione (Beppe Severgnini)

Ultima modifica di alex783 : 19-10-2009 alle 21:14.
alex783 è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 21:32   #5
alex783
Senior Member
 
Iscritto dal: Jan 2009
Messaggi: 609
Marco, ho provato la tua soluzione, ma mi dà questo errore:
"Errore 1 Nessun overload per 'mio_metodo' corrispondente al delegato 'System.Threading.ParameterizedThreadStart'"

Come mai?
Poi, perché nella dichiarazione del metodo mio_metodo hai messo il tipo dato generico object anziché int? è necessario fare questo?
__________________
L'iPad? Potrebbe esserci gente che, pur d'avere il nuovo gadget, si mette a leggere i libri. Questa sì sarebbe una rivoluzione (Beppe Severgnini)
alex783 è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 21:40   #6
MarcoGG
Senior Member
 
L'Avatar di MarcoGG
 
Iscritto dal: Dec 2004
Messaggi: 3210
Quote:
Originariamente inviato da alex783 Guarda i messaggi
Marco, ho provato la tua soluzione, ma mi dà questo errore:
"Errore 1 Nessun overload per 'mio_metodo' corrispondente al delegato 'System.Threading.ParameterizedThreadStart'"

Come mai?
Poi, perché nella dichiarazione del metodo mio_metodo hai messo il tipo dato generico object anziché int? è necessario fare questo?
Esatto : private void mio_metodo(object I)
E' richiesto dal ParameterizedThreadStart.
MarcoGG è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 21:47   #7
alex783
Senior Member
 
Iscritto dal: Jan 2009
Messaggi: 609
ora funziona... però mi sa che così sia possibile passare solo un dato al metodo... se avessi bisogno di passare ad esempio due variabili, mi restituisce l'errore di prima... certo, potrei passare un arraylist che contiene le diverse variabili che mi servono, ma non la trovo molto elegante come soluzione.

Grazie comunque, per ora questa soluzione va benone!
__________________
L'iPad? Potrebbe esserci gente che, pur d'avere il nuovo gadget, si mette a leggere i libri. Questa sì sarebbe una rivoluzione (Beppe Severgnini)
alex783 è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 21:57   #8
gugoXX
Senior Member
 
L'Avatar di gugoXX
 
Iscritto dal: May 2004
Città: Londra (Torino)
Messaggi: 3692
Il perche' stampi sempre 3 con il tuo metodo e' presto detto.
Nonostante tu abbia lanciato ciascuno Thread dentro il ciclo, i Thread partono e processati schedulati quando vuole lo shcedulatore.
Il tuo output significa che da ciascuno viene raggiunta l'istruzione
MessageBox.Show("'i' corrente vale: "+i.ToString());
quando in realta' il ciclo chiamante e' gia' terminato, ovvero quando la i vale gia' 3.

Per come risolvere problemi come questo, ci sono tanti modi. Alcuni eleganti, alcuni efficienti, alcuni preferiti.


Relativamente a .net 2.0 / 3.5 puro, per eseguire un metodo piu' volte in maniera asincrona, non e' necessario scomodare i Thread, ma bastano i delegate (che tanto usi comunque per dichiarare il Thread, quindi un passo in meno)

Senza scomodare .Net4.0 o 3.5 con le parallel extensions, sotto 3.5 puro lo scrirverei cosi', (sotto 2.0 risulta solo un po' piu' verboso).
Codice:
for (int i = 0; i < 3; i++)
{
   Action<int> newAct = new Action<int>{ i=> MetodoDaEseguire(i)};
   newAct.BeginInvoke(i, null, null);
}
Non stampare nulla a video nei MetodoDaEseguire (come quelle MessageBox)Se devi fare uscire qualcosa a video (tipicamente no), allora usa i Dispatcher per sincronizzare.
Male forzare ApartmentState, dato che non e' assicurato il risutalto, ora e' deprecata e occorrerebbe usare TrySetApartmentState (che come dice il nome non ne assicura di per se il risultato)

Per un compito come questo non userei Thread o ThreadPool, sebbene sia possibile.
__________________
Se pensi che il tuo codice sia troppo complesso da capire senza commenti, e' segno che molto probabilmente il tuo codice e' semplicemente mal scritto.
E se pensi di avere bisogno di un nuovo commento, significa che ti manca almeno un test.
gugoXX è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 21:58   #9
MarcoGG
Senior Member
 
L'Avatar di MarcoGG
 
Iscritto dal: Dec 2004
Messaggi: 3210
Quote:
Originariamente inviato da alex783 Guarda i messaggi
ora funziona... però mi sa che così sia possibile passare solo un dato al metodo... se avessi bisogno di passare ad esempio due variabili, mi restituisce l'errore di prima... certo, potrei passare un arraylist che contiene le diverse variabili che mi servono, ma non la trovo molto elegante come soluzione.
Non "un dato", un oggetto, con tutti i vantaggi che comporta.
Puoi passare una List di Objects e nel Metodo eseguire i cast opportuni. Elegante o meno, è la soluzione giusta per questo tipo di approccio.
Altra soluzione è avere l'istanza di una classe che esponga il Metodo. I campi della classe sono i "parametri", e una volta impostati, si lancia il Thread su quel Metodo, senza passare alcun parametro, e senza bisogno di ParameterizedThreadStart.

In ogni caso ParameterizedThreadStart è opzionale, in quanto il compilatore è in grado di utilizzarlo da solo, se rileva il passaggio di un argomento. Questo codice funziona ugualmente :

Codice:
                Thread T = new Thread(mio_metodo);
                T.SetApartmentState(ApartmentState.STA);
                this.listOfThreads.Add(T);
                T.Start(i);
MarcoGG è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 22:16   #10
alex783
Senior Member
 
Iscritto dal: Jan 2009
Messaggi: 609
Quote:
Originariamente inviato da gugoXX Guarda i messaggi
Il perche' stampi sempre 3 con il tuo metodo e' presto detto.
Nonostante tu abbia lanciato ciascuno Thread dentro il ciclo, i Thread partono e processati schedulati quando vuole lo shcedulatore.
Il tuo output significa che da ciascuno viene raggiunta l'istruzione
MessageBox.Show("'i' corrente vale: "+i.ToString());
quando in realta' il ciclo chiamante e' gia' terminato, ovvero quando la i vale gia' 3.

Per come risolvere problemi come questo, ci sono tanti modi. Alcuni eleganti, alcuni efficienti, alcuni preferiti.


Relativamente a .net 2.0 / 3.5 puro, per eseguire un metodo piu' volte in maniera asincrona, non e' necessario scomodare i Thread, ma bastano i delegate (che tanto usi comunque per dichiarare il Thread, quindi un passo in meno)

Senza scomodare .Net4.0 o 3.5 con le parallel extensions, sotto 3.5 puro lo scrirverei cosi', (sotto 2.0 risulta solo un po' piu' verboso).
Codice:
for (int i = 0; i < 3; i++)
{
   Action<int> newAct = new Action<int>{ i=> MetodoDaEseguire(i)};
   newAct.BeginInvoke(i, null, null);
}
Non stampare nulla a video nei MetodoDaEseguire (come quelle MessageBox)Se devi fare uscire qualcosa a video (tipicamente no), allora usa i Dispatcher per sincronizzare.
Male forzare ApartmentState, dato che non e' assicurato il risutalto, ora e' deprecata e occorrerebbe usare TrySetApartmentState (che come dice il nome non ne assicura di per se il risultato)

Per un compito come questo non userei Thread o ThreadPool, sebbene sia possibile.
Ho dimenticato di specificare ad inizio del thread che ho necessità di restare relegato a .NET 2.0.

L'istruzione MessageBox.Show chiaramente non c'è nel metodo vero e proprio che uso nella mia applicazione, ma è servito a me per capire il comportamente del metodo.

Credo che l'uso dei thread sia necessario al mio caso, dal momento che metodoDaEseguire contiene codice per gestire DotNetZip, quindi ho necessità di dare all'utente la possibilità - ad esempio - di sospendere momentaneamente una compressione ZIP.

Grazie per la spiegazione del mio problema, ma comunque non capisco come faccia "i" ad assumere il valore "3" se il limite imposto nel ciclo di "for" è 2. Boh, mi sembra incomprensibile...
__________________
L'iPad? Potrebbe esserci gente che, pur d'avere il nuovo gadget, si mette a leggere i libri. Questa sì sarebbe una rivoluzione (Beppe Severgnini)
alex783 è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 22:23   #11
alex783
Senior Member
 
Iscritto dal: Jan 2009
Messaggi: 609
Quote:
Originariamente inviato da MarcoGG Guarda i messaggi
Non "un dato", un oggetto, con tutti i vantaggi che comporta.
Puoi passare una List di Objects e nel Metodo eseguire i cast opportuni. Elegante o meno, è la soluzione giusta per questo tipo di approccio.
Altra soluzione è avere l'istanza di una classe che esponga il Metodo. I campi della classe sono i "parametri", e una volta impostati, si lancia il Thread su quel Metodo, senza passare alcun parametro, e senza bisogno di ParameterizedThreadStart.

In ogni caso ParameterizedThreadStart è opzionale, in quanto il compilatore è in grado di utilizzarlo da solo, se rileva il passaggio di un argomento. Questo codice funziona ugualmente :

Codice:
                Thread T = new Thread(mio_metodo);
                T.SetApartmentState(ApartmentState.STA);
                this.listOfThreads.Add(T);
                T.Start(i);
Grazie ancora! in effetti è molto interessante la possibilità di poter passare un oggetto e non un semplice tipo valore. Comunque devo rivedere un po' questa parte del mio programma, anzi, mi sa che la devo ripensare, anche perché in questo modo poi andrei a scontrarmi con una eccezione di cross-thread (o almeno immagino, visto che poi da quei thread, ho necessità di modificare i controlli, in particolare le progressbar , di una form istanziata da un thread diverso )
__________________
L'iPad? Potrebbe esserci gente che, pur d'avere il nuovo gadget, si mette a leggere i libri. Questa sì sarebbe una rivoluzione (Beppe Severgnini)
alex783 è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 22:43   #12
alex783
Senior Member
 
Iscritto dal: Jan 2009
Messaggi: 609
mi chiedevo... ma l'eventuale eccezione di cross-thread, potrei risolverlo con i delegati, giusto?

domani mattina provo, ora vado a nanna... grazie a tutti!
__________________
L'iPad? Potrebbe esserci gente che, pur d'avere il nuovo gadget, si mette a leggere i libri. Questa sì sarebbe una rivoluzione (Beppe Severgnini)
alex783 è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 23:07   #13
gugoXX
Senior Member
 
L'Avatar di gugoXX
 
Iscritto dal: May 2004
Città: Londra (Torino)
Messaggi: 3692
Quote:
Originariamente inviato da alex783 Guarda i messaggi
Grazie per la spiegazione del mio problema, ma comunque non capisco come faccia "i" ad assumere il valore "3" se il limite imposto nel ciclo di "for" è 2. Boh, mi sembra incomprensibile...
Vediamo se la capisci cosi:
Codice:
for (int i=0;i<3;i++)
{
//Fai qualunque cosa, volendo anche nulla
}
Console.WriteLine(i);
Cosa viene stampato a video?
__________________
Se pensi che il tuo codice sia troppo complesso da capire senza commenti, e' segno che molto probabilmente il tuo codice e' semplicemente mal scritto.
E se pensi di avere bisogno di un nuovo commento, significa che ti manca almeno un test.
gugoXX è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2009, 23:38   #14
tomminno
Senior Member
 
Iscritto dal: Oct 2005
Messaggi: 3306
Quote:
Originariamente inviato da alex783 Guarda i messaggi
P.S: perché dovrei evitare le ArrayList? le ho sempre usate, mai un problema, e le trovo molto comode
Il principale motivo è che ArrayList è una collezione di object (retaggio del vecchio .NET 1.x), con tutto quello che comporta, boxing e unboxing di tipi valore, rischio di infilarci oggetti di natura differente.
Usa List<Thread> e non te ne pentirai.
tomminno è offline   Rispondi citando il messaggio o parte di esso
Old 20-10-2009, 08:08   #15
alex783
Senior Member
 
Iscritto dal: Jan 2009
Messaggi: 609
Quote:
Originariamente inviato da gugoXX Guarda i messaggi
Vediamo se la capisci cosi:
Codice:
for (int i=0;i<3;i++)
{
//Fai qualunque cosa, volendo anche nulla
}
Console.WriteLine(i);
Cosa viene stampato a video?
Vero. E sì, perché il ciclo "for" funziona così:
i=0 --> è minore di 3? si, allora aggiungi +1
i=1 --> è minore di 3? si, allora aggiungi +1
i=2 --> è minore di 3? si, allora aggiungi +1
i=3 --> è minore di 3? no, esci dal ciclo

Grazie mille, non ci avevo proprio pensato.


Quote:
Originariamente inviato da tomminno Guarda i messaggi
Il principale motivo è che ArrayList è una collezione di object (retaggio del vecchio .NET 1.x), con tutto quello che comporta, boxing e unboxing di tipi valore, rischio di infilarci oggetti di natura differente.
Usa List<Thread> e non te ne pentirai.
Capito. Beh, allora cambio, anche per imparare e usare qualcosa di nuovo
Grazie!
__________________
L'iPad? Potrebbe esserci gente che, pur d'avere il nuovo gadget, si mette a leggere i libri. Questa sì sarebbe una rivoluzione (Beppe Severgnini)
alex783 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


WoW: Midnight, Blizzard mette il primo, storico mattone per l'housing e molto altro WoW: Midnight, Blizzard mette il primo, storico ...
Ecovacs Goat O1200 LiDAR Pro: la prova del robot tagliaerba con tagliabordi integrato Ecovacs Goat O1200 LiDAR Pro: la prova del robot...
Recensione Samsung Galaxy S26+: sfida l'Ultra, ma ha senso di esistere? Recensione Samsung Galaxy S26+: sfida l'Ultra, m...
Zeekr X e 7X provate: prezzi, autonomia fino a 615 km e ricarica in 13 minuti Zeekr X e 7X provate: prezzi, autonomia fino a 6...
Marathon: arriva il Fortnite hardcore Marathon: arriva il Fortnite hardcore
Nutanix accelera la migrazione da VMware...
Nutanix apre ai neocloud: piattaforma mu...
Nutanix amplia la piattaforma cloud e st...
Le fotografie dell'eclissi solare e dell...
Oracle AI Database si potenzia con nuove...
Russia offline: blackout internet mobile...
Gemini, Google investe 30 milioni per la...
Roborock Qrevo Edge S5A: 17.000 Pa, acqu...
Resa pubblica la foto della ''Terra che ...
Il robot che ha piegato 200 scatole di f...
SteelSeries Aerox 3 Wireless Gen 2: nuov...
"Quasi sociopatico": Sam Altma...
Star Wars Eclipse in difficoltà: ...
Gestione del team e romance organiche: l...
Intel lancia Core Ultra X9 378H: hardwar...
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: 22:22.


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