|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Senior Member
Iscritto dal: Oct 2003
Città: Pisa/Cosenza
Messaggi: 1364
|
[Java] Programmazione concorrente e thread
Ciao, sto esaurendo su un progetto per l'esame di programmazione concorrente spero di trovare qualcuno che mi possa chiarire qualche dubbio.
Per adesso solo una domandina rapida rapida: E' possibile che un thread in un ciclo while(condizione) monopolizzi la CPU in modo da non permettere ad un altro thread di cambiare tale condizione facendo andare il programma in loop infinito?
__________________
![]() |
![]() |
![]() |
![]() |
#2 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Dal punto di vista di Java sì, non c'è una politica di fairness prestabilita.
|
![]() |
![]() |
![]() |
#3 | |
Senior Member
Iscritto dal: Oct 2003
Città: Pisa/Cosenza
Messaggi: 1364
|
Quote:
Devo implementare una receiveAny su un array di porte. Ho un semaforo su cui il server si sospende se tutte le porte sono vuote (nessun mittente ha lasciato un messaggio). Il server sospeso su questo semaforo viene svegliato dal mittente prima di aver depositato il messaggio. Purtroppo lo devo svegliare prima di aver effettivamente lasciato il messaggio perché le porte sono sincrone, cioè quando il mittente inserisce il messaggio si sospende in attesa che qualcuno faccia receive. Per superare l'inconveniente che il server svegliato dal semaforo porteVuote non trovi alcun messaggio perché il mittente perde il controllo della CPU dopo aver segnalato il server ma prima di aver effettivamente inserito il messaggio ho fatto così: Codice:
private int testa_porte()throws InterruptedException{ int porta = -1; for(int i=0; i<array.length; i++){ if(array[i].haveSospesi()){ porta = i; break; } } porteVuote.acquire(); while(porta == -1){ System.out.println("Cerco..."); for(int i=0; i<array.length; i++){ if(array[i].haveSospesi()){ porta = i; break; } } Thread.sleep(500); } return porta; } Se tutte le porte sono vuote si sospende su porteVuote. Quando viene risvegliato entra in un ciclo while che gli fa testare le porte finché non trova effettivamente il messaggio, che in linea teorica prima o poi deve esserci perché qualche mittente ha fatto signal al server. E' sbagliata come soluzione? Idee migliori?
__________________
![]() |
|
![]() |
![]() |
![]() |
#4 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Se è sempre vera la condizione:
quando il server si sveglia esiste necessariamente almeno un messaggio in coda allora funziona per forza. Non è neanche detto che sia un brutta soluzione perchè per pause di durata certa e molto breve uno spinning è vantaggioso rispetto ad una struttura di controllo concorrente relativamente più complicata come può essere un swap. Lo sleep io lo metterei prima, magari un po' più breve (un bel po' più breve, diciamo 1ms anche se la granularità dello sleep una volta era sui 10-15ms). Alternative idealmente ce ne sarebbero. Il protocollo che hai non è strano. Io entro, lascio un messaggio sulla coda in entrata della mail box 1 e resto in attesa sulla coda di uscita della stessa mail box. Il server viene svegliato dal gestore delle MailBox, prende il messaggio della mail box 1, lo processa e inserisce la risposta nella coda di uscita della MailBox 1. Io che ero in attesa sulla coda di uscita della MailBox1 me ne vado con la mia risposta. Alla fine tutto dipende da dove puoi mettere le mani. |
![]() |
![]() |
![]() |
#5 | |
Senior Member
Iscritto dal: Oct 2003
Città: Pisa/Cosenza
Messaggi: 1364
|
Quote:
Quindi è impossibile per me mittente segnalare il server dopo aver lasciato il messaggio. In pratica lo segnalo un attimo prima... ma questa cosa ha il difetto che il mittente potrebbe segnalare e perdere il controllo della CPU prima di aver lasciato il messaggio... per questo il server svegliato va a cercare un messaggio che ancora non c'è.. ed è per questo che ho necessità del ciclo while dopo il risveglio...
__________________
![]() |
|
![]() |
![]() |
![]() |
#6 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Mi sono espresso male:
quando il server si sveglia esisterà necessariamente a breve un messaggio in coda |
![]() |
![]() |
![]() |
#7 |
Registered User
Iscritto dal: May 2009
Messaggi: 300
|
Segnala entrambe le cose. Prima segnali che verrà messo un messaggio, quindi il server si sveglia, ma andrà in wait sulla coda di quella porta. Appena il client (dopo aver segnalato la sua intenzione di inserimento) effettua realmente l'inserimento allora il server si sveglia e riceve il messaggio. Ma non so se ho capito bene il problema...
|
![]() |
![]() |
![]() |
#8 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Basterebbe il secondo segnale ma se il thread che deve segnalare si blocca subito dopo il deposito del messaggio chi lo manda?
|
![]() |
![]() |
![]() |
#9 |
Registered User
Iscritto dal: May 2009
Messaggi: 300
|
Scusate ora ho le idee un po' confuse perchè è passato troppo tempo dal corso di SISOP... Il codice non è formale.
Codice:
MsgQueue coda[N] = {EMPTY, ..., EMPTY}; Semaforo sem = 0; void serverBody() { while(1) { // Corpo del server eseguito ciclicamente... System.out.println("Controllo la presenza di messaggi.\n"); sem.wait(); System.out.println("Mi stanno inviando dei messaggi!\n"); System.out.println("Vediamo chi è...\n"); int c = 0; while(1) { if(!(coda[c].vuota())) { System.out.println("Messaggio da Client" + c +"!!!"); Msg msg = coda[c].pop(); Msg newMsg = elabora(msg.info()); sendTo(c, newMsg); System.out.println("Servito!"); break; } c=(c+1)%N; } } } Msg inviaMessaggio(int mittente, Msg msg) { System.out.println("Segnalo al server.\n"); sem.signal(); System.out.println("Accodo messaggio.\n"); coda[mittente].push(msg); Msg msg = receiveFrom(SERVER); return msg; } ATTENZIONE: Questa soluzione non gestisce i messaggi in ordine. Il client i che al tempo t1 invia un messaggio potrebbe essere gestito dal server dopo il client j che al tempo t2>t1 ha inviato il proprio messaggio. Una soluzione un pò più "FAIR" è la seguente: Codice:
MsgQueue coda[N] = {EMPTY, ..., EMPTY}; Semaforo sem = 0; int c = 0; void serverBody() { while(1) { // Corpo del server eseguito ciclicamente... System.out.println("Controllo la presenza di messaggi.\n"); sem.wait(); System.out.println("Mi stanno inviando dei messaggi!\n"); System.out.println("Vediamo chi è...\n"); while(1) { if(!(coda[c].vuota())) { System.out.println("Messaggio da Client" + c +"!!!"); Msg msg = coda[c].pop(); Msg newMsg = elabora(msg.info()); sendTo(c, newMsg); System.out.println("Servito!"); break; } c=(c+1)%N; } } } Msg inviaMessaggio(int mittente, Msg msg) { System.out.println("Segnalo al server.\n"); sem.signal(); System.out.println("Accodo messaggio.\n"); coda[mittente].push(msg); Msg msg = receiveFrom(SERVER); return msg; } Ultima modifica di Ikon O'Cluster : 23-08-2009 alle 18:08. |
![]() |
![]() |
![]() |
#10 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Quello è uno spinning ed è la soluzione che già sta usando.
|
![]() |
![]() |
![]() |
#11 |
Registered User
Iscritto dal: May 2009
Messaggi: 300
|
si ma mi convince più fatta come l'ho impostata io...
![]() |
![]() |
![]() |
![]() |
#12 |
Senior Member
Iscritto dal: Oct 2003
Città: Pisa/Cosenza
Messaggi: 1364
|
Stavo pensando... non sarebbe meglio se inserissi un time out nello spinning?
![]() Se il mittente dopo aver fatto signal sul semaforo per qualsiasi ragione non consegnasse il messaggio? avrei un Server in loop?
__________________
![]() |
![]() |
![]() |
![]() |
#13 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Se non sei certo al mille per mille che il messaggio ci sarà lo spin non va più bene.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
![]() |
![]() |
![]() |
#14 | |
Senior Member
Iscritto dal: Oct 2003
Città: Pisa/Cosenza
Messaggi: 1364
|
Quote:
Ma ipotizziamo il caso assurdo che il thread mittente venga killato dal SO dopo la signal (so che non è possibile ma facciamo finta che lo sia).. la soluzione è un time out? Ci ho pensato per giorni e giorni e lo spinning sembra l'unica soluzione.
Unica soluzione lo spinning! ...o no? ![]() ![]() ![]()
__________________
![]() Ultima modifica di luxorl : 07-09-2009 alle 15:43. |
|
![]() |
![]() |
![]() |
#15 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Come "come faccio ad essere certo"?
![]() Devi guardare le istruzioni che stanno tra la notifica e il deposito, stabilire quali sono le condizioni che possono generare un mancato deposito e usarle per controllare lo spin. Se la condizione è che il thread possa essere magicamente ucciso allora metterai come condizione del loop l'esistenza di almeno un thread client. Il time-out pigliatutto è una soluzione un po' povera perchè una volta che scatta non sai perchè il messaggio sia andato perduto.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
![]() |
![]() |
![]() |
#16 | |
Senior Member
Iscritto dal: Oct 2003
Città: Pisa/Cosenza
Messaggi: 1364
|
Quote:
Più che "almeno l'esistenza di un thread client", che potrebbe essere true anche se il mittente muore, potrei fare un while con condizione: "finché il thread mittente è vivo && non trovo messaggio" Questo si potrebbe fare solo se esiste un modo in Java per sapere se il thread con id x è ancora vivo. Esiste? ![]() Se esiste potrei salvarmi l'id del thread mittente prima che questo notifichi il server e nello spinning verificare che il thread non sia misteriosamente scomparso. Che ne pensi? ![]()
__________________
![]() Ultima modifica di luxorl : 07-09-2009 alle 17:13. |
|
![]() |
![]() |
![]() |
#17 |
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
@luxorl: che tipo di scenario stai cercando di gestire? il tipico caso dell'utonto che inciampa sul cavo dell'alimentazione staccando la spina al pc?
![]()
__________________
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) |
![]() |
![]() |
![]() |
#18 |
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Se l'unica possibilità è che il Thread muoia inspiegabilmente allora tranquillizzati perchè i Thread non muoiono mai di morte violenta - a differenza ad esempio dei processi.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
![]() |
![]() |
![]() |
#19 | |
Senior Member
Iscritto dal: Oct 2003
Città: Pisa/Cosenza
Messaggi: 1364
|
Quote:
![]() Grazie ![]()
__________________
![]() |
|
![]() |
![]() |
![]() |
#20 | |
Senior Member
Iscritto dal: Oct 2003
Città: Pisa/Cosenza
Messaggi: 1364
|
Quote:
![]() ![]()
__________________
![]() |
|
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 21:36.