Torna indietro   Hardware Upgrade Forum > Software > Programmazione

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
Narwal Flow: con il mocio orizzontale lava i pavimenti al meglio
Narwal Flow: con il mocio orizzontale lava i pavimenti al meglio
Grazie ad un mocio rotante che viene costantemente bagnato e pulito, Narwal Flow assicura un completo e capillare lavaggio dei pavimenti di casa. La logica di intellignza artificiale integrata guida nella pulizia tra i diversi locali, sfruttando un motore di aspirazione molto potente e un sistema basculante per la spazzola molto efficace sui tappeti di casa
Panasonic 55Z95BEG cala gli assi: pannello Tandem e audio senza compromessi
Panasonic 55Z95BEG cala gli assi: pannello Tandem e audio senza compromessi
Con un prezzo di 2.999 euro, il Panasonic Z95BEG entra nella fascia ultra-premium dei TV OLED: pannello Primary RGB Tandem, sistema di raffreddamento ThermalFlow, audio Technics integrato e funzioni gaming avanzate lo pongono come un punto di riferimento
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 23-12-2009, 16:27   #1
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
[C++] Qt multithreading

Ho un quesito per quanto riguarda la programmazione con più di 2 thread....

se io ho 3 classi, una la struttura dati, le altre due devono accedervi spesso. Siccome non è possibile prevedere e conseguentemente sincronizzare gli accessi, utilizzo la classe QMutex per evitare accessi contemporanei....
La mia domanda è...
questa classe la utilizzo dentro i metodi pubblici della classe per i dati? è corretto?

Non mi interessa inserire QMutex dentro le altre due, ok?

Quindi dentro ogni metodo per esempio un metodo "get" farei così:
Codice:
QString charon::get_Host()
{
    QString temp;
    Mutex.lock();
    temp = Host;
    Mutex.unlock();
    return(temp);
}
dove "Host" è un elemento della struttura dati.
secondo voi?
Grazie.

Ultima modifica di Teo@Unix : 23-12-2009 alle 16:29.
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 24-12-2009, 01:55   #2
Black imp
Senior Member
 
Iscritto dal: Nov 2000
Città: MILANO
Messaggi: 2662
ad occhio e croce si. si sincronizza la classe che ha i dati cui si vuole accedere in modo esclusivo. quindi nei metodi della classe con i dati, che devono essere chiamati dalle altre due classi, si alza un mutex nella parte di codice chiamato critical race, che di solito è un membro - privato direi - della classe dati. quando uno arriva e trova il mutex lockato aspetta. occhio ai deadlock.
Black imp è offline   Rispondi citando il messaggio o parte di esso
Old 24-12-2009, 09:15   #3
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
Il valore di host viene mai cambiato ? Sui valori read-only non c'è bisogno di alcuna sincronizzazione.
La sincronizzazione c'è bisogno solamente in caso di read e write concorrenti o di write concorrenti su operazioni non atomiche.
Per andare oltre dovresti studiarti qualche manuale sulla programmazione concorrente, perché esistono tanti, ma tanti trucchi per diminuire i conflitti sulle risorse.

Ultima modifica di cionci : 24-12-2009 alle 09:26.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 24-12-2009, 09:28   #4
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
In realtà, viene cambiato inizialmente, quando solo un thread è attivo, quindi si, dopo verrà solo letto.
In questo caso non dovrebbe essere necessaria la mutex.

La mia idea relativamente al progetto "di prova" di cui avevo mostrato alcune parti di codice nell'altro post, era di associare un thread ad ogni porta da scansionare, in modo da aumentare di molto la velocità di esecuzione. Il programmino l'ho realizzato per ora solo con due thread. Quello che si occupa della scansione soffre dei timeout della connect().

Perciò avevo pensato di provare definendo 4 thread.
Questi appena finiranno il lavoro con la loro porta andranno a prendersi la prossima e via dicendo fino all'ultima... per ora ho un pò di problemi con il buffer dei risultati ....
ora ho escluso un problema di uso errato di mutex.... resta da vedere come gestire al meglio thread del genere....

Se questa domanda ha un senso,
Come fareste idealmente per gestire più thread?

edit: a ok, non avevo letto la tua modifica, si si comunque mi stò studiando la faccenda....
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 24-12-2009, 09:49   #5
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 ha senso creare un thread per ogni porta da scansionare. Per diversi validi motivi:
- l'ip che scansioni molto probabilmente ti rileverà come una attacco DoS
- l'efficienza, dopo un certo numero di thread, si va a perdere
- il costo della creazione di un thread, seppur basso, è sempre un costo

Quindi io ti consiglio un tot di thread, magari aumentabile tramite l'interfaccia grafica (numero di porte scansionate contemporaneamente). Che so, da 4-5 a non più di 10.
Questo è detto "pool di thread". Questi thread non verranno creati e distrutti ad ogni scansione, ma verranno creati all'inizio e distrutti alla fine di tutte le scansioni.
Dovrai fornire al pool di thread i dati su cui lavorare. Col sistema dei segnali-slot è veramente semplice avere la notifica del completamente del lavoro, non c'è nemmeno bisogno di lavorare troppo di mutex o gestire la concorrenza sui dati.
Quando un thread avrà completato il suo lavoro emetterà un segnale (magari fornendo l'indice del thread che ha finito il lavoro o il suo puntatore) e si metterà in attesa su un QSemaphore.
Questo segnale sarà collegato ad uno slot che avrà il compito di:
- raccogliere il risultato
- fornire al thread un nuova porta su cui andare a lavorare
- riavviare il thread andando ad agire sul semaforo
Nel subclassing di QThread potresti aggiungere un metodo connect(const QString &IP, const int port) che fa le ultime due cose.
Quando crei e avvii il thread potrebbe automaticamente andarsi bloccare sul QSemaphore in attesa che il chiamante vada a fornirgli la porta su cui lavorare con connect (basta inizializzare il QSemaphore a 0).

Ultima modifica di cionci : 24-12-2009 alle 09:57.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 24-12-2009, 10:12   #6
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
grazie chiarissimo,
dunque un semaforo mi fungerebbe da parcheggio...
perfetto avevo tentato di fare questa parte creandomi una routine nella classe MainWindow che gestiva proprio 4 thread...
così mi sembra semplice. Provo.
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 25-12-2009, 22:10   #7
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
Causa i consueti riti Natalizi non ho avuto molto tempo per provare,

ho però letto un pò la guida e ho visto che il "pool di threads" è una classe vera e propria, ho letto anche che, se il mio inglese non mi tradisce, occorre reimplementare QRunnable, nel senso che bisogna creare una classe derivata da QRunnable?

Quel che ho fatto è:

Nella classe MainWindow, dichiarata una classe derivata da QThreadPool.
Devo ora crearmi anche una classe QRunnable? E poi dichiarare in QThreadPool i miei thread QRunnable?
In questa metterei la connect() ecc...

spero di essermi spiegato bene...
Grazie.

Ultima modifica di Teo@Unix : 25-12-2009 alle 22:15.
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 10:27   #8
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
Ma non importa. Non sapevo nemmeno che esistesse
Per i tuoi scopi va più che bene un approccio più semplice. Almeno entri meglio nell'ottica dei thread e della loro gestione. Con QThreadPool, da quanto leggo, tutto il lavoro sui thread viene nascosto.
QThreadPool può essere comoda quando ci sono molti compiti diversi che possono essere svolti dai thread.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 10:53   #9
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
Già, siccome nel mio programmino di prova il compito è sempre le stesso, niente QThreadPool....

A questo punto ciò che farei è:
1 una classe che contiene il metodo per la scansione [scanthread]
2 la solita classe MainWindow (mantegno quella della prima versione del programma) [MainWindow]
3 la classe struttura dati (anche questa è la medesima) [charon]

Ora, nel costruttore di MainWindow creo 4 elem. scanthread.
Quindi mi hai parlato di QSemaphore per gestirli...
però non saprei bene, anche dagli esempi proposti non ho trovato nulla di simile..... QSemaphore mi sembra molto simile a QMutex....

Alla run() dei thread potrei anche fargli ritornare il puntatore del thread stesso... ma non ho capito bene come utilizzarlo dopo per controllare i threads....

Thanks.
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 11:02   #10
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
Usando segnali e slot non hai bisogno della classe per condividere i dati. Infatti puoi recuperare i dati ed assegnarne di nuovi su cui lavorare direttamente della classe del tuo thread, perché il thread è fermo sul semaforo, quindi non ci sarai mai concorrenza.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 11:08   #11
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
Quote:
Originariamente inviato da cionci Guarda i messaggi
perché il thread è fermo sul semaforo, quindi non ci sarai mai concorrenza.
sono un pò disorientato riguardo a questo punto però, cosa intendi per "fermo sul semaforo"?
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 11:20   #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
Quote:
Originariamente inviato da Teo@Unix Guarda i messaggi
sono un pò disorientato riguardo a questo punto però, cosa intendi per "fermo sul semaforo"?
Hai scritto tu "dunque un semaforo mi fungerebbe da parcheggio...", quindi credevo che avessi capito che l'esecuzione di un acquire su un semaforo rosso implica il blocco del thread. Il thread va risvegliato solo dopo che avrai inserito in nuovi dati su cui dovrà andare a lavorare eseguendo una release.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 11:33   #13
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
forse ho capito,
la mia run del thread è corretto abbia questo prototipo:
ScanThread* ScanThread::run(QHostAddress host,unsigned int port,short timeout)
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 11:36   #14
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 si era detto che appena eseguivi la run il thread si andava a bloccare sul semaforo ?
I dati su cui lavorare glieli puoi fornire dopo, con un metodo della classe del thread (che andrà anche a risvegliarlo).
Creati il pool di thread in modo che siano tutti bloccati in attesa di riceve le informazioni per partire.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 13:12   #15
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
...

dovrò passargli il semaforo però... umh?
ScanThread* run(QSemaphore*);

cioè dovrò per forza di cose passare il puntatore del semaforo al costruttore del thread. giusto?

Nel momento che il thread avrà finito farà sem.acquire() bloccandosi finche in mainwindow non eseguo sem.release().... ma posso utilizzare i metodi del thread per passargli i dati se esso è bloccato sul semaforo....

..scusa, ma stò faticando con questa parte....
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 14:08   #16
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 importa, il semaphoro lo puoi creare come variabile membro del thread.
Poi dopo andrai a chiamare, ad esempio:

thread->connect(......):

In cui passerai i dati su cui il thread andrà a lavorare.
In fondo alla conncect chiamerai la release sul semaforo.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 16:59   #17
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
Potrebbe essere una valida implementazione dell classe thread?
Ti sembra giusto l'uso dei semafori? (non ho provato nulla)

Codice:
#ifndef SCANTHREAD_H
#define SCANTHREAD_H

#include <QThread>
#include <QTcpSocket>
#include <QHostAddress>
#include <QString>
#include <QSemaphore>

class ScanThread : public QThread
{
    Q_OBJECT
private:
    //Dati
    unsigned int ThisPort;
    short int ThisTimeout;
    QString ThisHost;
    QTcpSocket socket;
    QString buffer;
    QSemaphore semaphore;
    //Metodi
    void ResolveService(unsigned int);
    
public:
    //Metodi pubblici
    ScanThread();
    void run();
    QString get_buffer();
public slots:
    void AwakeningProcess(unsigned int,QString,short);
};

#endif // SCANTHREAD_H

Codice:
#include "scanthread.h"

ScanThread::ScanThread()
{
    semaphore(0);
}

void ScanThread::run()
{
    while(semaphore.acquire(1))
    {
        socket.connectToHost(ThisHost,Thisport);
        if(socket.waitForConnected(ThisTimeout*1000))
        {
            buffer.append(tr("Rilevata porta %1 aperta - ").arg(ThisPort));
            ResolveService(port);
        }
    }
}

void ScanThread::ResolveService(unsigned int port)
{
    struct servent* service;
    if((service = getservbyport(htons(port),"tcp")) == NULL)
        buffer.append(tr("Impossibile risalire al servizio in esecuzione sulla porta\n"));
    else
        buffer.append(tr("%1 in esecuzione\n").arg(service->s_name));    
}

void ScanThread::AwakeningProcess(unsigned int port,QString Host,short timeout)
{
    ThisPort = port;
    ThisTimeout = timeout;
    ThisHost = Host;
    semaphore.release(1);
}
l'ultima funzione qui sopra dovrebbe passargli i parametri e svegliare il thread... mmmm che ne pensi?

Ultima modifica di Teo@Unix : 26-12-2009 alle 17:01.
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 17:19   #18
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
Va benissimo
Ottima scelta del while per il ciclo, ma acquire non torna alcun valore, è void.
Quindi dovresti mettere la acquire all'interno del ciclo e fare un while(1).

L'unico problema è questo:

Codice:
ScanThread::ScanThread()
{
    semaphore(0);
}
Non può funzionare così, devi utilizzare una lista di inizializzazione In quanto in quel punto lì, semaphore è già stato inizializzato. Comunque in questo caso non serve perché il QSemaphore viene già inizializzato a zero.

Ultima modifica di cionci : 26-12-2009 alle 17:21.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 26-12-2009, 17:59   #19
Teo@Unix
Senior Member
 
L'Avatar di Teo@Unix
 
Iscritto dal: Mar 2009
Messaggi: 753
Ok, ho modificato opportunamente.

Ora, questione gestione dei threads.........

Lo faccio nella classe mainwindow naturalmente.... siccome non posso piantarci un ciclo che crei attese se nò sarei punto capo...... avevo pensato di avviarne inizialmente uno, praticamente nello slot associato al pulsante start metterei:
thread0->AwakeningProcess(CurPort,Host,timeout);
va a chiamare il metodo del mio thread e fa eseguire al thread un nuovo ciclo con i nuovi dati.....
se ci sono più di una porta obiettivo avvio gli altri... il tutto sarebbe così:
(anche se non mi pare molto elegante)

Codice:
     CurPort = Sport;
    thread0->AwakeningProcess(CurPort,Host,timeout);
    if(CurPort==Eport) {}//Ho finito...
    CurPort++;
    thread1->AwakeningProcess(CurPort,Host,timeout);
    if(CurPort==Eport) {}//Ho finito...
    CurPort++;
    thread2->AwakeningProcess(CurPort,Host,timeout);
    if(CurPort==Eport) {}//Ho finito...
    CurPort++;
    thread3->AwakeningProcess(CurPort,Host,timeout);

Nel caso le porte sono più di 4....
avevo pensato di collegare il segnale finished() per ogni thread
con la funzione:
Codice:
void MainWindow::NextThread(ScanThread* thread)
{
    ScanThread* CurrentThread = thread;
    CurrentThread->AwakeningProcess(++CurPort,Host,timeout);
}
che incrementa la porta corrente e riavvia il thread per una nuova scansione, in questo modo i thread dovrebbeo essere sempre impegnati.
IL problema che ho incontrato è che nella funzione connect() non posso pasare un argomento allo slot, vuole solo i tipi....
Codice:
 connect(thread0,SIGNAL(sleep()),this,SLOT(NextThread(ScanThread*)))
quindi come passo il puntatore del thread disponibile?

Hai idee migliori per gestire i threads?

Grazie molte.

Ultima modifica di Teo@Unix : 26-12-2009 alle 18:21.
Teo@Unix è offline   Rispondi citando il messaggio o parte di esso
Old 27-12-2009, 09:22   #20
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
Codice:
void MainWindow::NextThread(ScanThread* thread)
{
    ScanThread* CurrentThread = thread;
    //qui devi anche recuperare il risultato
    CurrentThread->AwakeningProcess(++CurPort,Host,timeout);
}
Inoltre devi emettere un segnale per risolvere il problema
http://doc.trolltech.com/4.5/signals...-small-example
Crea un signal nella classe del thread che si chiama ad esempio workDone(ScanThread* thread). Lo devi collegare allo slot NextThread tramite la connect.
Dopo che hai emesso il segnale devi fare la acquire sul semaforo.
cionci è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


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...
HONOR Magic V5: il pieghevole ultra sottile e completo! La recensione HONOR Magic V5: il pieghevole ultra sottile e co...
Recensione Google Pixel 10 Pro XL: uno zoom 100x assurdo sempre in tasca (e molto altro) Recensione Google Pixel 10 Pro XL: uno zoom 100x...
Intel: il processo produttivo 14A sar&ag...
Fiat porta in Algeria la produzione di G...
Spazio Lenovo riapre a Milano. Cosa camb...
Prime foto di ID. Polo GTI: Volkswagen p...
BYD ha grandi novità per IAA: la ...
ASML investe 1,3 miliardi in Mistral AI ...
Tecnologia d'altri tempi e benessere del...
Come va il modem Apple C1 di iPhone 16e?...
smart alla IAA Mobility 2025, elogia i n...
Star Wars, chiusa l'asta per la spada or...
Nova Launcher è morto? Il fondato...
PayPal offre un anno gratuito di Perplex...
Borderlands 4: svelati gli orari di pubb...
ECOVACS mostra il futuro delle faccende ...
Prezzo shock per Samsung Galaxy S25 e S2...
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: 15:12.


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