Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Google Pixel 10 è compatto e ha uno zoom 5x a 899€: basta per essere un best-buy?
Google Pixel 10 è compatto e ha uno zoom 5x a 899€: basta per essere un best-buy?
Google Pixel 10 è uno smartphone che unisce una fotocamera molto più versatile rispetto al passato grazie allo zoom ottico 5x, il supporto magnetico Pixelsnap e il nuovo chip Tensor G5. Il dispositivo porta Android 16 e funzionalità AI avanzate come Camera Coach, mantenendo il design caratteristico della serie Pixel con miglioramenti nelle prestazioni e nell'autonomia. In Italia, però, mancano diverse feature peculiari basate sull'AI.
Prova GeForce NOW upgrade Blackwell: il cloud gaming cambia per sempre
Prova GeForce NOW upgrade Blackwell: il cloud gaming cambia per sempre
L'abbonamento Ultimate di GeForce NOW ora comprende la nuova architettura Blackwell RTX con GPU RTX 5080 che garantisce prestazioni tre volte superiori alla precedente generazione. Non si tratta solo di velocità, ma di un'esperienza di gioco migliorata con nuove tecnologie di streaming e un catalogo giochi raddoppiato grazie alla funzione Install-to-Play
Ecovacs Deebot X11 Omnicyclone: niente più sacchetto per lo sporco
Ecovacs Deebot X11 Omnicyclone: niente più sacchetto per lo sporco
Deebot X11 Omnicyclone implementa tutte le ultime tecnologie Ecovacs per l'aspirazione dei pavimenti di casa e il loro lavaggio, con una novità: nella base di ricarica non c'è più il sacchetto di raccolta dello sporco, sostituito da un aspirapolvere ciclonico che accumula tutto in un contenitore rigido
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 07-07-2009, 17:33   #1
giorgio_82
Junior Member
 
Iscritto dal: Jul 2009
Messaggi: 4
[Java] problemi con invokeLater()

Salve,
è il mio primo post e non so se sono nella sezione giusta. In caso contrario perdonatemi.
Ho il seguente codice:
Codice:
package main;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;


public class Server extends JFrame {

	public static int port = 2222;
	
	private JScrollPane jScrollPane1;
    private JTextArea textArea;

    public Server() {
        initComponents();
        setVisible(true);
        try {
			ServerSocket ss = new ServerSocket(port);
			while (true) {
				textArea.append("in attesa...\n");
				Socket socket = ss.accept();
				DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
				DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
				String s = dis.readUTF();
				textArea.append(s+"\n");
				textArea.append("richiesta effettuata\n");
				socket.close();
			}
		} catch (Throwable e) {
			e.printStackTrace();
		}
    }

    private void initComponents() {

        jScrollPane1 = new JScrollPane();
        textArea = new JTextArea();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        textArea.setColumns(25);
        textArea.setEditable(false);
        textArea.setRows(15);
        jScrollPane1.setViewportView(textArea);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(125, Short.MAX_VALUE)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(109, 109, 109))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(97, 97, 97)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(107, Short.MAX_VALUE))
        );

        pack();
    }

    public static void main(String args[]) {
    	SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				new Server();
			}
		});
    }
}
Se provo ad eseguire mi viene fuori la finestra aperta solo in parte, perchè secondo me sbaglio qualcosa quando vado ad utilizzare la invokeLater() e il programma mi si sospende sull'accept.
Se tolgo, nel main, la chiamata alla invokeLater, cioè faccio solo new Server(), il programma mi va, però ho il dubbio che non sia il modo più giusto di fare il tutto.
Mi potreste dire cosa sbaglio e come sarebbe più corretto realizzare l'applicazione!?
Vi ringrazio in anticipo.
Giorgio

Ultima modifica di giorgio_82 : 07-07-2009 alle 20:30.
giorgio_82 è offline   Rispondi citando il messaggio o parte di esso
Old 08-07-2009, 08:29   #2
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Quote:
Originariamente inviato da giorgio_82 Guarda i messaggi
Se provo ad eseguire mi viene fuori la finestra aperta solo in parte, perchè secondo me sbaglio qualcosa quando vado ad utilizzare la invokeLater() e il programma mi si sospende sull'accept.
Se tolgo, nel main, la chiamata alla invokeLater, cioè faccio solo new Server(), il programma mi va, però ho il dubbio che non sia il modo più giusto di fare il tutto.
Hai definito una classe Server che estende un JFrame (e quindi farà parte dell'interfaccia grafica della tua applicazione) ma dentro implementa anche le funzionalità di un server.

Come forse già sai, dato che usi l'invokeLater per accodare nella coda degli eventi di Swing la realizzazione di un nuovo oggetto Server, le operazioni programmatiche cha hanno come oggetto componenti di Swing visualizzabili vanno fatte eseguire all'Event Dispatcher Thread (EDT).
Fin qui tutto bene.

Il problema è che al momento della chiamata al costruttore [new Server()] eseguito dall'EDT, l'EDT stesso esegue: la initComponents() [usi NetBeans, vero?] e va bene, ma poi deve eseguire anche il ciclo dove c'è la accept() e le altre operazioni che fai con il ServerSocket.
A questo punto l'EDT rimane vincolato ad eseguire questo tuo codice (non viene mai "liberato" finchè rimane in vita il ciclo) e quindi non può continuare con il suo lavoro: cioè prelevare eventi dalla coda degli eventi di Swing ed eseguirli... In altre parole la grafica "si inchioda" (per sempre, tra l'altro, dato che non verrà mai terminato il ciclo while...)

Qui trovi un ottimo tutorial sulle basi di Swing dove è spiegato tutto per filo e per segno (e in modo molto più chiaro di come potrei fare io) già nelle prime pagine. Fortemente consigliato
__________________

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)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 08-07-2009, 13:27   #3
giorgio_82
Junior Member
 
Iscritto dal: Jul 2009
Messaggi: 4
Grazie mille per la risposta. Leggero il tutorial con attenzione. Comunque se ho ben capito devo far fare i compiti del server ad un altro thread e non all'EDT? Devo cioè mettere il while(true) {.....} nel run di un altro thread?
Un'altra cosa: come ho già detto, se tolgo l'invokeLater() e nel main chiamo direttamente new Server(); l'applicazione mi va. Quindi, evidentemente il thread che si occupa della grafica e il thread che si occupa di fare da server sono diversi? Ma allora l'invokeLate() non servirebbe?
Ancora grazie,
Giorgio
giorgio_82 è offline   Rispondi citando il messaggio o parte di esso
Old 08-07-2009, 14:06   #4
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Quote:
Originariamente inviato da giorgio_82 Guarda i messaggi
Grazie mille per la risposta. Leggero il tutorial con attenzione. Comunque se ho ben capito devo far fare i compiti del server ad un altro thread e non all'EDT? Devo cioè mettere il while(true) {.....} nel run di un altro thread?
Precisamente.
Se devi ancora lavorare con Swing quel tutorial è veramente utile
Inpratica dovresti incapsulare quella parte in un Runnable da lanciare subito.
Poi magari può capitare che a seguito di operazioni che avvengono in thread "esterni" uno deve aggiornare o comunque compiere azioni grafiche; da cui la neccessità di sapere come sincronizzare il tutto.
Non a caso nel JDK esistono delle classi di utility, tipo la SwingWorker, proprio per agevolare operazioni del genere. Alla fine del tutorial linkato c'è una breve introduzione proprio su SwingWorker.

Quote:
Originariamente inviato da giorgio_82 Guarda i messaggi
Un'altra cosa: come ho già detto, se tolgo l'invokeLater() e nel main chiamo direttamente new Server(); l'applicazione mi va. Quindi, evidentemente il thread che si occupa della grafica e il thread che si occupa di fare da server sono diversi? Ma allora l'invokeLate() non servirebbe?
Ancora grazie,
Giorgio
Il fatto è che se lanci la tua interfaccia grafica senza incapsulare il tutto in un Runnable che piazzi con invokeLater nella AWT-Event Queue, la tua interfaccia grafica è potenzialmente soggetta ad errori di rendering (artefatti grafici) e/o altri comportamenti anomali.

In pratica può succedere che per interfacce semplici (come quella in oggetto) il problema può non verificarsi finchè fai girare l'applicativo per poco tempo e sempre sotto lo stesso sistema: magari i problemi cominciano a manifestarsi più tardi, quando l'applicazione la complessità dell'interfaccia cresce o quando si prova a far girare l'applicativo sotto diversi sistemi...

La morale della favola è che è sempre errato, dal punto di vista architetturale, il non rispetto della condizione percui tutte le operazioni relative a componenti Swing devono essere eseguite dall'EDT.
E questo proprio perchè l'architettura di Swing è a thread singolo.
__________________

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 : 08-07-2009 alle 14:10.
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 09-07-2009, 11:35   #5
Caldwell83
Senior Member
 
L'Avatar di Caldwell83
 
Iscritto dal: Nov 2007
Città: Bergamo
Messaggi: 307
Quote:
Originariamente inviato da banryu79 Guarda i messaggi
Precisamente.
Se devi ancora lavorare con Swing quel tutorial è veramente utile
Inpratica dovresti incapsulare quella parte in un Runnable da lanciare subito.
Poi magari può capitare che a seguito di operazioni che avvengono in thread "esterni" uno deve aggiornare o comunque compiere azioni grafiche; da cui la neccessità di sapere come sincronizzare il tutto.
Non a caso nel JDK esistono delle classi di utility, tipo la SwingWorker, proprio per agevolare operazioni del genere. Alla fine del tutorial linkato c'è una breve introduzione proprio su SwingWorker.
Mi intrufolo nella discussione.

Ho notato che nella api di java 1.5 la classe SwingWorker non esiste, quindi come si fa?
Si passano agli altri tread i riferimenti agli oggetti della swing in modo che li possano modificare quando succede qualcosa?
Caldwell83 è offline   Rispondi citando il messaggio o parte di esso
Old 09-07-2009, 11:47   #6
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Quote:
Originariamente inviato da Caldwell83 Guarda i messaggi
Si passano agli altri tread i riferimenti agli oggetti della swing in modo che li possano modificare quando succede qualcosa?
Credo di sì, (almeno è quello che farei io) con l'accortezza che il thread "esterno" (esterno nel senso che non è l'EDT) quando ha finito e deve fare in modo che la grafica si aggiorni, incapsuli a sua volta le operazioni sui componenti grafici in un nuovo Runnable da accodare con il solito invokeLater.

Ovviamente tutta questa trafila viene fatta solo per quelle operazioni così pesanti che, se lasciate svolgere dall'EDT, lo impegnano per troppo tempo tanto da rallentare sensibilmente la reattività della GUI della applicazione.
Altrimenti va bene evitare di sbattersi e lasciar sgobbare l'EDT.

Penso che l'utente PGI-bis possa darti informazioni più precise in merito, data la sua esperienza.
__________________

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)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 09-07-2009, 15:00   #7
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Quote:
Originariamente inviato da Caldwell83 Guarda i messaggi
Si passano agli altri tread i riferimenti agli oggetti della swing in modo che li possano modificare quando succede qualcosa?
I riferimenti agli oggetti Swing devono restare nell'EDT. Ad esempio uno potrebbe pensare di dire:

//nel thread EDT
final JFrame frame = new JFrame()
... bla bla
frame.setVisible(true);

new Thread() { public void run() { fai qualcosa con frame....} };//errato

Non va bene perchè l'edt continua a manipolare il frame - per visualizzarlo, spostarlo, aggiornarlo eccetera - mentre il secondo thread cerca di fare qualcosa con lo stesso frame. Vale per tutti i componenti Swing.

Non è possibile usare la sincronizzazione perchè non abbiamo modo di dire all'EDT "tutte le operazioni che fai sul componente devi farle usando il monitor X": possiamo dirlo solo ai thread di cui abbiamo il controllo.

Bisogna quindi separare la parte del programma che gestisce l'interfaccia da eventuali altri Thread e far comunicare le due parti attraverso oggetti-messaggio immutabili o sincronizzati. Ad esempio se sono in un Thread che legge del testo da un socket:

//Thread NON edt
String text = leggi testo da socket

Per passare il testo letto ad una JTextArea dirò una cosa tipo:

Codice:
final String message = text;
EventQueue.invokeLater(new Runnable() {
    public void run() {
        jtextArea.append(message);
    }
});
Per oggetti mutable basta usare il messaggio come monitor:

//Thread non EDT
Point value = leggi un punto da socket

Codice:
final Point message = new Point();
synchronized(message) { message.x = value.x; message.y = value.y; }
EventQueue.invokeLater(new Runnable() {
    public void run() {
        synchronized(message) {
            jtextArea.append(message.x + "," + message.y);
        }
    }
});
Ci sono anche altre soluzioni. Ad esempio se lo scambio di messaggi è intenso si può usare una coda concorrente - java.util.concurrent.LinkedBlockingQueue - ed un thread che la consuma passando il contenuto all'edt. La coda garantisce che i valori letti siano gli stessi esistenti al momento dell'immissione.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 09-07-2009, 15:29   #8
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Quote:
//Thread non EDT
Point value = leggi un punto da socket
Codice:
final Point message = new Point();
synchronized(message) { message.x = value.x; message.y = value.y; }
EventQueue.invokeLater(new Runnable() {
    public void run() {
        synchronized(message) {
            jtextArea.append(message.x + "," + message.y);
        }
    }
});
Ci sono anche altre soluzioni. Ad esempio se lo scambio di messaggi è intenso si può usare una coda concorrente - java.util.concurrent.LinkedBlockingQueue - ed un thread che la consuma passando il contenuto all'edt. La coda garantisce che i valori letti siano gli stessi esistenti al momento dell'immissione.
Un chiarimento (premetto che di sincronizzazione ci capisco poco o niente): ma cosa garantisce che il valore di message.x passato al metodo append della text area dall'EDT sia ancora lo stesso, rispetto a quando impostato dal thread esterno?

Se il lasso di tempo cha passa tra setting del valore da parte del thread esterno che passa il malloppo all'EDT e il momento in cui l'EDT effettivamente recupera l'istruzione/evento da processare è abbastanza ampio, in caso di potenziale accesso concorrente all'oggetto referenziato da messagge non c'è il rischio che un altro thread ci modifichi sotto i piedi il valore?
E' giusto come ragionamento (cioè esiste la possibilità che si verifichi tale scenario)?
E' in questi casi che potremmo cercare garanzie al riguardo tamite quella LinkedBlockingQueue che hai nominato? Ehm, a proposito, in sostanza che fa? Blocca l'accesso all'oggetto finchè non viene prelevato dalla coda? Oppure tiene solo una copia dei valori tali quali erano all'epoca dell'inserimento?

Spero di non aver scassato troppo con tutte queste domande, eh
__________________

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)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 10-07-2009, 16:24   #9
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Se ho due Thread A e B entrambi in esecuzione, A crea un Point - oggetto tipicamente mutabile - di coordinate (100, 75) e lo passa a B tout court il punto che B riceve può essere un qualsiasi valore tra un punto di coordinate (0,0), un punto di coordinate (100,0) e un punto (0,75). Questi sono i valori che B può legittimamente attendersi.

La sincronizzazione ci dice che se ho un monitor M e il Thread A assegna al punto le sue coordinate sincronizzandosi su M una successiva lettura del punto da parte di un Thread B sincronizzato su M legge necessariamente i valori precedentemente assegnati da A.

Nota bene: precedentemente. La sincronizzazione non è perpetua. Abbiamo un punto P. C'è un metodo che assegna delle coordinate a P sincronizzandosi su P stesso e poi delega la lettura di P all'EDT. Una cosa tipo:

Codice:
private final Point p = new Point();//final = p non è mai null

public void set(int x, int y) {
    synchronized(p) { p.x = x; p.y = y; }
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            synchronized(p) {
                leggi i valori p.x e p.y;
            }
        }
    });
}
Qui ho la garanzia che l'aggiornamento dei valori di p è visibile all'EDT ma non ho una garanzia di ordine. Il codice garantisce che se il Thread A dice:

set(1, 1);
set(2, 2);
set(3, 3);

l'edt può vedere una qualsiasi tripla composta dai punti ( (1,1), (2,2), (3,3) ) e non vedrà mai (0,1) o (0,0) o (1,0) o (0,2) o (3,1).

Vale a dire che non esiste una race condition riguardante i valori del punto ma esiste una race condition tra le invocazioni di set da parte del Thread A e le letture dell'EDT.

Per evitare anche la seconda race condition occorre generare un nuovo punto ad ogni invocazione di set e passare quel punto all'EDT come messaggio: così facendo ogni invocazione di set genera un nuovo punto e l'eventuale invocazione plurima di set da parte del Thread A non lede la lettura dei valori successivamente impostati da parte dell'EDT.

Codice:
private final Point p = new Point();

public synchronized void set(int x, int y) {
    p.x = x;
    p.y = y;
    final Point message = new Point();
    synchronized(message) {
        message.x = x;
        message.y = y;
    }
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            synchronized(message) {
                leggi message.x e message.y
            }
        }
    }
}
Rispetto a prima qui c'è un synchronized in più perchè "p" è supposto essere un campo mentre prima non c'erano campi. Cosa succede se un Thread invoca tre volte il metodo set adesso?

Succede che quel Thread crea tre punti diversi - uno ad ogni invocazione - ed ognuno di quei punti è passato all'edt per una lettura sincronizzata. Ergo ora se il Thread A dice:

set(1, 1);
set(2, 2);
set(3, 3);

l'Edt legge necessariamente:

(1,1)
(2,2)
(3,3)

Capita perchè rispetto ad A le tre invocazioni successive di set sono necessariamente ordinate e in più ognuna di queste crea un nuovo punto - e non agisce su un unico punto come prima.

Ma anche qui c'è race condition se anzichè parlare di un solo Thread A iniziamo ad avere due Thread, A e B, che invocano set. Qui occorrerà stabilire se esista un ordine necessario tra le invocazioni di set da parte di A e B e in caso affermativo si procederà a garantire tale ordine.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 10-07-2009, 16:51   #10
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Grazie della risposta: causa programmazione forzata e scarse ore di sonno non ci ho capito quasi una mazza (e va beh, la verità è che di multithreading non ne so nulla, a parte quelle cosine base che leggi sui tutorial), ma mi riservo la possibilità di leggere e riflettere con calma in futuro ed eventualmente tampinarti con altre domande.
__________________

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)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 13-07-2009, 09:33   #11
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Eccomi di nuovo
Ho riletto e ri-riflettuto con calma e matita alla mano sul tuo esempio, e sono riuscito a capirlo. Ammazza' il multithreading è molto più complesso di quanto sospettassi

Comunque mi rimane un dubbio da dipanare, e una domanda da porre.
Il dubbio:
Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
Codice:
private final Point p = new Point();

public synchronized void set(int x, int y) {
    p.x = x;
    p.y = y;
    final Point message = new Point();
    synchronized(message) {
        message.x = x;
        message.y = y;
    }
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            synchronized(message) {
                leggi message.x e message.y
            }
        }
    }
}
Rispetto a prima qui c'è un synchronized in più perchè "p" è supposto essere un campo mentre prima non c'erano campi.
Preche dici che nell'esempio che hai fatto, precedente a quello quotato, non c'erano campi? il punto "p" non era comunque un campo, anche se dichiarato final? Mi sono perso qualcosa?

La domanda che rimane aperta:
Quote:
Originariamente inviato da PGI-Bis
Ma anche qui c'è race condition se anzichè parlare di un solo Thread A iniziamo ad avere due Thread, A e B, che invocano set. Qui occorrerà stabilire se esista un ordine necessario tra le invocazioni di set da parte di A e B e in caso affermativo si procederà a garantire tale ordine.
Hai descritto esattamente la situazione che ipotizzavo: anche se sincronizzo l'operazione di scrittura nei campi del punto che poi il mio thread A passa all'EDT, solo in un secondo momento l'EDT preleverà l'operazione da eseguire con quel punto dalla coda: e se nel frattempo un altro thread B accede al punto in scrittura e ne cambia il valore dei campi?

E' neccessario usare due punti distinti, uno per thread, e ogni thread poi delega le operazioni all'EDT sul proprio punto? E' possibile farlo usando un solo punto, condiviso da entrabi i thread e dall'EDT?

Ciao e grazie dei chiarimenti

P.S.: per chiarezza, l'ordine neccessario tra le invocazioni di set da parte di A e B sarebbe il seguente:
Per ogni invocazione di set sul punto da parte di uno dei due thread, non può essere eseguita un'altra invocazione di set da parte dell'altro thread finchè le operazioni su quel punto delegate all'EDT non siano state espletate.

Ovvero se A set"P" e inserisce il messaggio "P" nella coda degli eventi di EDT, B non può fare set"P" finchè l'operazione delegata non sia stata effettivamente eseguita da EDT (B rimane in attesa su "P").
__________________

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 : 13-07-2009 alle 09:40.
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 13-07-2009, 16:46   #12
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Il prima era riferito al prima di prima. Là non c'erano campi.

La seconda questione era diversa. Il problema che poni non c'è per via della sincronizzazione sul metodo.

synchronized void set(...)

esclude che due Thread possano eseguire contemporaneamente questo metodo. C'è sempre un solo thread per volta che esegue set. Non è quindi possibile che mentre il Thread A modifica il punto in set un Thread B faccia lo stesso, almeno non tramite il metodo set. Poichè il metodo set genera un nuovo punto da dare in pasto all'EDT non sussiste neppure il problema di un'eventuale sovrapposizione tra l'esecuzione di set da parte di un Thread A o B e la lettura del valore impostato da parte dell'EDT.

I punti non sono due, sono uno più un nuovo punto ad ogni invocazione di set.

E' possibile farlo con un solo punto? Sì, se ad ogni set blocchiamo il thread invocante finchè l'edt non abbia terminato la lettura.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 13-07-2009, 17:31   #13
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
La seconda questione era diversa. Il problema che poni non c'è per via della sincronizzazione sul metodo.

synchronized void set(...)

esclude che due Thread possano eseguire contemporaneamente questo metodo. C'è sempre un solo thread per volta che esegue set. Non è quindi possibile che mentre il Thread A modifica il punto in set un Thread B faccia lo stesso, almeno non tramite il metodo set.
Ok grazie, ma questo mi era chiaro già dal tuo esempio.

Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
Poichè il metodo set genera un nuovo punto da dare in pasto all'EDT non sussiste neppure il problema di un'eventuale sovrapposizione tra l'esecuzione di set da parte di un Thread A o B e la lettura del valore impostato da parte dell'EDT.

I punti non sono due, sono uno più un nuovo punto ad ogni invocazione di set.
Anche questo caso l'avevo capito, sempre grazie al tuo esempio.

Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
E' possibile farlo con un solo punto? Sì, se ad ogni set blocchiamo il thread invocante finchè l'edt non abbia terminato la lettura.
Ecco, questo è lo scenario su cui mi sono interrogato, dopo aver letto il tuo primo post a risposta di Caldwell.
Quello che mi (ti) chiedo è: come si fa?
__________________

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)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 14-07-2009, 12:00   #14
malocchio
Senior Member
 
L'Avatar di malocchio
 
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
OK, mi avete fatto venire mal di testa, per cui adesso scappo a mangiare...

No dai scherzo, ho capito quasi tutto. (veramente molto molto interessante)


Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
Per oggetti mutable basta usare il messaggio come monitor:

//Thread non EDT
Point value = leggi un punto da socket

Codice:
final Point message = new Point();
synchronized(message) { message.x = value.x; message.y = value.y; }
EventQueue.invokeLater(new Runnable() {
    public void run() {
        synchronized(message) {
            jtextArea.append(message.x + "," + message.y);
        }
    }
});

Ora, un paio di domande:

1. l'oggetto message è un'instanza appena creata, a cosa serve il blocco sincronizzato su di esso synchronized(message) { message.x = value.x; message.y = value.y; } ?? Se l'oggetto è stato creato all'interno del metodo, c'è un solo thread in grado di accedervi, per cui a cosa serve acquisire il lock su message?

2. Tutto questo (ovvero il fatto che message sicuramente non viene modificato prima di essere praticamente utilizzato dall'EDT) funziona solo se reference di message non "escono" dal blocco di codice del metodo. In caso contrario un codice "esterno" potrebbe modificare message prima che l'EDT l'abbia utilizzato, o sbaglio?

Spero di non aver detto ca@@ate, ho fame e, si sa, a stomaco vuoto si ragiona meglio !

Ciao
__________________
malocchio è offline   Rispondi citando il messaggio o parte di esso
Old 14-07-2009, 13:18   #15
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Quote:
Originariamente inviato da malocchio Guarda i messaggi
1. l'oggetto message è un'instanza appena creata, a cosa serve il blocco sincronizzato su di esso synchronized(message) { message.x = value.x; message.y = value.y; } ?? Se l'oggetto è stato creato all'interno del metodo, c'è un solo thread in grado di accedervi, per cui a cosa serve acquisire il lock su message?
E' la variabile message ad essere locale ma se quella variabile è, come nel nostro caso, un riferimento - a oggetto - e quell'oggetto ha dei campi allora i campi a cui accedi tramite quella variabile non sono locali ma risiedono nella memoria condivisa - tra i thread. Da cui la necessità della sincronizzazione.

Quote:
2. Tutto questo (ovvero il fatto che message sicuramente non viene modificato prima di essere praticamente utilizzato dall'EDT) funziona solo se reference di message non "escono" dal blocco di codice del metodo. In caso contrario un codice "esterno" potrebbe modificare message prima che l'EDT l'abbia utilizzato, o sbaglio?
E' corretto, qui l'istanziazione di un nuovo punto esclusivamente dedicato all'EDT è parte del meccanismo che rende quel codice concorrente. In effetti è lo stesso principio della coda di consumazione solo che la coda che usiamo è quella predefinita per gli eventi AWT/Swing.

Per quanto riguarda l'uso di un solo punto l'algoritmo è breve. Supponendo che read sia l'operazione dell'EDT sul punto e set sia l'invocazione del nostro metodo che imposta i valori del punto successivamente letto dall'EDT ciò che vogliamo è:

finchè l'EDT non ha terminato l'operazione read qualsiasi thread che invochi set è bloccato;
quando l'EDT termina l'operazione read sveglia uno qualsiasi dei thread sospesi in set.

La coppia set-read con relativi campi di controllo potrebbe essere:

Codice:
	final Point point = new Point();
	final Lock lock = new ReentrantLock();
	final Condition stop = lock.newCondition();
	boolean reading;

	public void set(int x, int y) throws InterruptedException {
		lock.lock();
		try {
			while(reading) {
				stop.await();
			}
			point.x = x;
			point.y = y;
			reading = true;
			EventQueue.invokeLater(new Runnable() {
				public void run() {
					read();
				}
			});
		} finally {
			lock.unlock();
		}
	}
	
	private void read() {
		lock.lock();
		try {
			int x = point.x;
			int y = point.y;
			appendText("Letto (" + x + "," + y + ")");
			reading = false;
			stop.signalAll();
		} finally {
			lock.unlock();
		}
	}
Qui "lock" ha la doppia funzione di escludere l'esecuzione concorrente di set e garantire la visibilità delle mutazione di point all'EDT e di reading ai thread che invocano set. Il Thread che invoca set blocca altri thread in attesa impostando reading a true. L'esecuzione di read da parte dell'EDT cambia il valore di reading da true a false e sblocca i thread in attesa su stop.

Ovviamente qui siamo nel caso scolastico. In realtà la faccenda richiede un po' più di codice perchè in un'applicazione reale noi dovremmo pensare anche alla possibilità che l'applicazione debba terminare mentre il nostro set-read è in funzione. Significa cioè che accando all'avvenuta lettura di point da parte dell'EDT esiste una seconda condizione che sblocca tutti i Thread in attesa, tale condizione è la richiesta di spegnimento del programma e a differenza di reading essa non deve condurre all'invocazione di read da parte dell'edt.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 14-07-2009, 14:14   #16
malocchio
Senior Member
 
L'Avatar di malocchio
 
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
E' la variabile message ad essere locale ma se quella variabile è, come nel nostro caso, un riferimento - a oggetto - e quell'oggetto ha dei campi allora i campi a cui accedi tramite quella variabile non sono locali ma risiedono nella memoria condivisa - tra i thread. Da cui la necessità della sincronizzazione.
Come sarebbe scusa? Ok, l'istanza (senza la enne, l'avrò sbagliato una decina di volte oggi) risiede nell'heap, e allora? Per accedervi è comunque necessario un reference che punti ad essa, cosa che altri thread non hanno...
Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
E' corretto, qui l'istanziazione di un nuovo punto esclusivamente dedicato all'EDT è parte del meccanismo che rende quel codice concorrente. In effetti è lo stesso principio della coda di consumazione solo che la coda che usiamo è quella predefinita per gli eventi AWT/Swing.

Per quanto riguarda l'uso di un solo punto l'algoritmo è breve. Supponendo che read sia l'operazione dell'EDT sul punto e set sia l'invocazione del nostro metodo che imposta i valori del punto successivamente letto dall'EDT ciò che vogliamo è:

finchè l'EDT non ha terminato l'operazione read qualsiasi thread che invochi set è bloccato;
quando l'EDT termina l'operazione read sveglia uno qualsiasi dei thread sospesi in set.

La coppia set-read con relativi campi di controllo potrebbe essere:

Codice:
	final Point point = new Point();
	final Lock lock = new ReentrantLock();
	final Condition stop = lock.newCondition();
	boolean reading;

	public void set(int x, int y) throws InterruptedException {
		lock.lock();
		try {
			while(reading) {
				stop.await();
			}
			point.x = x;
			point.y = y;
			reading = true;
			EventQueue.invokeLater(new Runnable() {
				public void run() {
					read();
				}
			});
		} finally {
			lock.unlock();
		}
	}
	
	private void read() {
		lock.lock();
		try {
			int x = point.x;
			int y = point.y;
			appendText("Letto (" + x + "," + y + ")");
			reading = false;
			stop.signalAll();
		} finally {
			lock.unlock();
		}
	}
Qui "lock" ha la doppia funzione di escludere l'esecuzione concorrente di set e garantire la visibilità delle mutazione di point all'EDT e di reading ai thread che invocano set. Il Thread che invoca set blocca altri thread in attesa impostando reading a true. L'esecuzione di read da parte dell'EDT cambia il valore di reading da true a false e sblocca i thread in attesa su stop.

Ovviamente qui siamo nel caso scolastico. In realtà la faccenda richiede un po' più di codice perchè in un'applicazione reale noi dovremmo pensare anche alla possibilità che l'applicazione debba terminare mentre il nostro set-read è in funzione. Significa cioè che accando all'avvenuta lettura di point da parte dell'EDT esiste una seconda condizione che sblocca tutti i Thread in attesa, tale condizione è la richiesta di spegnimento del programma e a differenza di reading essa non deve condurre all'invocazione di read da parte dell'edt.
Aiuto... Banryu dicevi che è complicato? Non sono mai arrivato ad implementare sistemi così complessi di sincronizzazione, mi sono fermato ai semafori (Semaphore), a scopo didattico. Devo ammettere che il multithreading è tanto interessante quanto pericoloso, e mi attira fortemente!
__________________
malocchio è offline   Rispondi citando il messaggio o parte di esso
Old 14-07-2009, 14:33   #17
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Il nostro punto message è creato in un metodo ma è poi passato ad un secondo thread, l'edt, tramite invokeLater.

Codice:
public void set() {
    final Point message = new Point(); //message è locale, message.x e message.y no
   EventQueue.invokeLater(new Runnable() {
       public void run() {
           message...
       }
   });
}
il run() è potenzialmente eseguito da un Thread diverso da quello che esegue set. Da cui la necessità di sincronizzare.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 14-07-2009, 14:36   #18
malocchio
Senior Member
 
L'Avatar di malocchio
 
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
Il nostro punto message è creato in un metodo ma è poi passato ad un secondo thread, l'edt, tramite invokeLater.

Codice:
public void set() {
    final Point message = new Point(); //message è locale, message.x e message.y no
   EventQueue.invokeLater(new Runnable() {
       public void run() {
           message...
       }
   });
}
il run() è potenzialmente eseguito da un Thread diverso da quello che esegue set. Da cui la necessità di sincronizzare.
In questo caso non abbiamo la certezza che il thread che andrà a leggere i campi di message verrà avviato DOPO le nostre chiamate a message.set() ??
__________________
malocchio è offline   Rispondi citando il messaggio o parte di esso
Old 14-07-2009, 14:47   #19
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Non ce l'abbiamo. Solo le azioni che vengono eseguite in uno stesso Thread avvengono nell'ordine in cui sono scritte nel codice.

run() e set() sono metodi eseguiti da Thread diversi. Secondo il modello di memoria possono essere eseguiti in qualsiasi ordine - perchè non essendo soggetti ad un vincolo happens-before le invocazioni possono essere riordinate.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 14-07-2009, 14:51   #20
malocchio
Senior Member
 
L'Avatar di malocchio
 
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
Quote:
Originariamente inviato da PGI-Bis Guarda i messaggi
Non ce l'abbiamo. Solo le azioni che vengono eseguite in uno stesso Thread avvengono nell'ordine in cui sono scritte nel codice.

run() e set() sono metodi eseguiti da Thread diversi. Secondo il modello di memoria possono essere eseguiti in qualsiasi ordine - perchè non essendo soggetti ad un vincolo happens-before le invocazioni possono essere riordinate.
Ma nello spezzone di codice in questione tu crei il Runnable DOPO le chiamate al set() e POI lo accodi in attesa dell'esecuzione, com'è possibile che il thread relativo a questo runnable parta in concorrenza con le chiamate set() ?

EDIT:

Se io scrivo
Codice:
System.out.println("1");

new Thread( new Runnable () {
	public void run () {
		System.out.println("2");
	}
}).start();
sono sicuro (in assenza di altri thread), verrà stampato
Codice:
1
2
O sbaglio?
__________________

Ultima modifica di malocchio : 14-07-2009 alle 14:56.
malocchio è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Google Pixel 10 è compatto e ha uno zoom 5x a 899€: basta per essere un best-buy? Google Pixel 10 è compatto e ha uno zoom ...
Prova GeForce NOW upgrade Blackwell: il cloud gaming cambia per sempre Prova GeForce NOW upgrade Blackwell: il cloud ga...
Ecovacs Deebot X11 Omnicyclone: niente più sacchetto per lo sporco Ecovacs Deebot X11 Omnicyclone: niente più...
Narwal Flow: con il mocio orizzontale lava i pavimenti al meglio Narwal Flow: con il mocio orizzontale lava i pav...
Panasonic 55Z95BEG cala gli assi: pannello Tandem e audio senza compromessi Panasonic 55Z95BEG cala gli assi: pannello Tande...
Novità dalle analisi dell'asteroi...
La PS6 sarà più potente del previsto: ec...
Sony svela Xperia 10 VII: è il nu...
Amazon Weekend da urlo: iPhone 16 a prez...
Spotify diffida ReVanced: chiesta la rim...
Spazzolini elettrici Oral-B iO in super ...
Samsung Galaxy Watch8 Classic e Watch7 a...
Blue Origin prosegue lo sviluppo di Blue...
Roborock Saros 10 e 10R dominano il merc...
Apple scatenata su Amazon: tutti gli sco...
Canon EOS C50 è la nuova videocam...
ASUS ProArt P16 arriva in Italia: la wor...
Fujifilm presenta l'obiettivo FUJINON GF...
Il grafene ha appena 'infranto' una legg...
Metroid Prime Beyond: arriva un trailer ...
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: 17:15.


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