Aus thread auf Formular zugreifen



  • Ja, jetzt bin ich schon schlauer.

    Mein jetziges Problem sieht allerdings so aus:

    Ich will mehrere Threads laufen lassen, die auf eine Variable zugreifen und diese z.B. immer um 1 erhöhen. Dass ich dafür soetwas wie eine "critical section" brauche ist mir klar.

    Wie kann ich aber die globale Variable ordentlich deklarieren ?

    Schon in der mainwindow.h includiere ich die thread.h-datei.

    In der thread.h soll dann die globale Variable deklariert werden:

    #ifndef THREAD_H
    #define THREAD_H
    
    #include <QThread>
    
    extern int abba;
    
    class MyThread : public QThread
    {
        Q_OBJECT
    
    public:
        virtual void run();
    
        signals:
        void neuezahl(int zahl);
    };
    
    #endif // THREAD_H
    

    ich bekomme immer den Fehler "multiple deklaration of 'abba'".

    Hat jemand einen Lösungsvorschlag ?



  • Das Problem ist gelöst.

    Wie kann ich n threads auf gleichzeitig starten ?

    Wenn ich 200 threads von Hand deklariere ist das irgendwie blöd.

    Das muss doch mit einer for-schleife funktionieren!

    for(int i = 0;i < = 100;i++)
    {
       Was muss hier rein ?  :) 
    }
    


  • Anscheinend funktioniert das mit QThreadpool. Dafür brauche ich aber ein QRunnable-objekt und kein QThread-objekt.

    Muss ich jetzt alles neu schreiben oder funktioniert das auch irgendwie mit QThread ?



  • Beliebig viele Objekte speichern?

    QList<MyThread*> threads;
    

    Und bitte brav aufpassen, dass der Thread auch den Scope überlebt (-> dynamische Speicherverwaltung).



  • Danke für deine Hilfe.

    Ich habe jetzt einfach in der Main-Klasse ein Thread-Array erstellt:

    private:
        Ui::MainWindow *ui;
        MyThread c[100];
    

    So starte ich die Threads:

    for(int i = 0;i < 50;i++)
        {
            connect(&c[i], SIGNAL(neuezahl(int)), this, SLOT(zahl(int)));
            connect(&c[i], SIGNAL(threadcount(int)), this, SLOT(showThreads(int)));
    
            c[i].start();
        }
    

    Jetzt kommt das misteriöse:

    Ich habe eine globale Variable definiert, auf die ich in allen erstellten Threads zugreifen will. Die Variable heißt "id" und wird vor thread-start auf 0 gesetzt. Dann soll sie bei jedem Thread hochzählen und jedem einzelnen Thread eine Id geben. Komischerweise ist "threadId" immer 1, egal wie viele Threads ich starte.

    void MyThread::run()
    {
        QMutex mutex;
    
        mutex.lock();
        id++;
        int threadId = id;
    
            while(current < proxy_count)
            {
                    current++;
            }
        mutex.unlock();
    }
    

    Woran liegt das ?



  • Lusches12345 schrieb:

    Woran liegt das ?

    Du hast Mutex nicht verstanden. Es muss GENAU EINE Mutex existieren, welche bei Zugriffen auf deine Variable gelockt wird.

    Deine connects bringen auch nicht viel. 1) sind das DirectConnections wegen 2) leben deine Threads im Main-Thread 3) seh ich nirgends ein "emit neuezahl(100)" o.Ä.



  • Du hast Mutex nicht verstanden. Es muss GENAU EINE Mutex existieren, welche bei Zugriffen auf deine Variable gelockt wird.

    Also muss ich eine Mutex global deklarieren ?

    #ifdef _extern_
    extern int proxy_count;
    extern int current;
    extern int threadsRunning;
    extern int id;
    extern QStringList proxyliste;
    extern QMutex mutex;
    #else
    int proxy_count = 0;
    int current = 0;
    int threadsRunning = 0;
    int id = 0;
    QStringList proxyliste;
    QMutex mutex;
    #endif
    

    so sehen jetzt meine globalen variablen in der Thread.h aus.

    vieleicht habe ich die funktion zu stark gekürzt:

    void MyThread::run()
    {
    
        QString proxy;
    
        mutex.lock();
        ThreadPlus();
    
        id++;
        int threadId = id;
    
            while(current < proxy_count)
            {
    
                    current++;
                    proxy = proxyliste[current-1];
    
                    emit checking(proxy, threadId);
    
                    //Hier proxy testen
    
                    emit checked(true, proxy);
    
            }
    
        ThreadMinus();
        mutex.unlock();
    
    }
    

    Die emits funkionieren einwandfrei und ich bekomme auch eine Ausgabe im Main-Thread. Allerdings wird immer die gleiche Id bei emit

    checking(proxy, threadId);
    

    zurückgegeben.

    void MainWindow::checking(QString proxy, int id)
    {
        ui->EThreads->addItem("Checking " + proxy + " from ID: " + QString::number(id));
    }
    

    Irgendwas scheint da nicht 100%tig zu funktionieren 😕



  • Da sind so viele unbekannte. Was machen z.B. ThreadPlus() und ThreadMinus()?
    Kannst du dein Programm bitte auf das Problem reduzieren, so dass ein kompilierbares Minimalbeispiel entsteht? das .ui rausschmeißen, GUI händisch erstellen, alle rechnenden Komponenten entfernen, einfach deine Threadklasse, dein MainWindow, deine Anzeigekomponente. Dein geposteter Code sollte direkt kompilierbar sein.



  • Jetzt habe ich mal meinen alten Account wiederbelebt.

    void MyThread::ThreadPlus()
    {
        threadsRunning++;
        emit threadcount(threadsRunning);
    }
    
    void MyThread::ThreadMinus()
    {
        threadsRunning--;
        emit threadcount(threadsRunning);
    }
    

    threadcount wird dann im Main-Thread dazu verwendet, die anzahl der laufenden Threads anzuzeigen. Das funktioniert aber leider auch nicht. threadsRunning ist immer = 1 wenn die Threads laufen.

    Hier das Minimalbeispiel:

    mainwindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    #include <QThreadPool>
    
    #define _extern_
    #include "thread.h"
    #undef _extern_
    
    namespace Ui {
        class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
        MyThread c[100];
    
    private slots:
        void on_pushButton_2_clicked();
        void on_pushButton_clicked();
        void showThreads(int);
    
        void checking(QString proxy, int id);
        void checked(bool type, QString proxy);
    };
    
    #endif // MAINWINDOW_H
    
    mainwindow.cpp:
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include <QMessageBox>
    
    #define _extern_
    #include "thread.h"
    #undef _extern
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::showThreads(int threads)
    {
        ui->statusBar->showMessage("Threads running: " + QString::number(threads));
        update();
    }
    
    void MainWindow::on_pushButton_clicked()
    {
    
        id = 0;
    
        for(int i = 0;i < 100;i++)
        {
            connect(&c[i], SIGNAL(threadcount(int)), this, SLOT(showThreads(int)));
    
            connect(&c[i], SIGNAL(checking(QString,int)), this, SLOT(checking(QString,int)));
            connect(&c[i], SIGNAL(checked(bool,QString)), this, SLOT(checked(bool,QString)));
    
            c[i].start();
        }
    
    void MainWindow::checked(bool type, QString proxy)
    {
    
        if(type)
        {
           ui->proxy_good->addItem(proxy);
        }
        else
        {
           ui->Proxy_bad->addItem(proxy);
        }
    
    }
    
    void MainWindow::checking(QString proxy, int id)
    {
        ui->EThreads->addItem("Checking " + proxy + " from ID: " + QString::number(id));
    }
    
    }
    

    thread.h

    #ifndef THREAD_H
    #define THREAD_H
    
    #include <QThread>
    #include <QRunnable>
    
    #include <QMutex>
    #include <QStringList>
    
    #include <QNetworkProxy>
    #include <QNetworkReply>
    #include <QNetworkAccessManager>
    
    #ifdef _extern_
    extern int proxy_count;
    extern int current;
    extern int threadsRunning;
    extern int id;
    extern QMutex mutex;
    #else
    int proxy_count = 0;
    int current = 0;
    int threadsRunning = 0;
    int id = 0;
    QMutex mutex;
    #endif
    
    class MyThread : public QThread
    {
        Q_OBJECT
    
    public:
    
        virtual void run();
    
    private:
    
        void ThreadPlus();
        void ThreadMinus();
    
    signals:
        void threadcount(int zahl);
        void checked(bool, QString);
        void checking(QString, int);
    };
    
    #endif // THREAD_H
    
    #define _extern_
    #include "thread.h"
    #undef _extern_
    
    void MyThread::ThreadPlus()
    {
        threadsRunning++;
        emit threadcount(threadsRunning);
    }
    
    void MyThread::ThreadMinus()
    {
        threadsRunning--;
        emit threadcount(threadsRunning);
    }
    
    void MyThread::run()
    {
        mutex.lock();
    
        ThreadPlus();
    
        id++;
        int threadId = id;
    
            while(current < 600)
            {
                    current++;
                    mutex.unlock();
    
                    emit checking("proxy-name", threadId);
                    emit checked(true, proxy);
    
                    mutex.lock();
            }
    
        ThreadMinus();
        mutex.unlock();
    }
    

    so sollte es kompilierbar sein.

    Grüße,
    Lusches AKA Schnurres



  • Bitte jetzt nochmal ohne dem ui-Kram (oder poste das .ui mit). Du hast da auto-connections drinnen (implizites connectSlotsByName aus dem ui), irgend welche anderen Widgets, etc.
    Außerdem fehlt die main. Du deklarierst irgendwo extern-Variablen, aber wo steht da die Definition?
    Extern ist sowieso nix gut (global eben, außerdem kann man nicht beliebig viele extern-Objekte erstellen). Kannst du das nicht in einer Klasse kapseln, eine Instanz davon erzeugen und den Threads mit auf den Weg geben?



  • Ich habe dir einfach das gesamte projekt unkompiliert hochgeladen (6kb). Hier ist der Link:
    http://www.xup.in/dl,11804133/untitled.zip/

    Bisher gibt es sowieso nur den Thread und noch eine funktion, die mir eine Datei öffnet und ausliest.

    Grüße,
    Lusches



  • Hat niemand eine Lösung für mich ?

    Wenn ihr wollt poste ich die vollständigen Dateien als Quellcode. Dann braucht ihr keine Angst vor Viren zu haben. 😕

    Grüße,
    Schnurres



  • Nimm in ThreadMinus() das "threadsRunning--" raus, dann kannst du dir vorstellen was passiert. Der Mutex locked vor dem ThreadPlus() und unlocked erst nach dem ThreadMinus. Das heißt, dass maximal ein Thread gerade in der run() arbeitet. Fängt er an, zählt er eins hoch, danach wieder eins runter, dann kommt der nächste Thread.

    Versuche ohne dem globalen Murkszeugs (sry :P) auszukommen, dass die Threads auch wirklich parallel arbeiten können.



  • Ich habe jetzt alles in eine Klasse ausgelagert und das Objekt global deklariert.
    Wie genau soll das jetzt mit dem Mutex funktionieren ?

    void MyThread::run()
    {
        QString proxy;
    
        ThreadPlus(); //->zugriff auf gem. variable
    
        gl.id++;//->zugriff auf gem. variable
        int threadId = gl.id;//->zugriff auf gem. variable
    
            while(gl.current < gl.proxyliste.count())//->zugriff auf gem. variable
            {
    
                   threadId = gl.id;//->zugriff auf gem. variable
    
                    proxy = gl.proxyliste[gl.current];//->zugriff auf gem. variable
    
                    emit checking(proxy, threadId);
                    emit checked(true, proxy);
    
            }
    
        ThreadMinus();//->zugriff auf gem. variable
    }
    

    So wie ich das sehe, muss fast überall mit dem Mutex-Objekt gelockt werden. 😕 😕 😕



  • Jetzt hast du nur das Problem verlagert. Anstatt vielen globalen Variablen hast du jetzt eine. Löst dein Problem aber nicht.

    Ich habe gemeint, dass du komplett ohne globalen Variablen arbeitest. Wenn du wirklich alle Threads parallel arbeiten lassen willst, und die run() am anfang den Mutex locked und am Ende erst wieder frei gibt, kann maximal ein Thread gleichzeitig laufen - wie schon einmal gesagt. Wenn du hingegen keine globale Mutex (weil keine globalen Variablen) hast, kann jeder Thread machen was er will, ohne auf die Synchronisation achten zu müssen.

    Als erstes musst du dir dazu natürlich überlegen, welche Informationen du wie und wohin verlagern kannst.
    Das Threads zählen kannst du zum Beispiel gleich ins MainWindow (welcher ja deine Threads startet) schieben. Vor dem Starten in MaineWindow Variable hochzählen, Connecte jedes finished()-Signal eines jeden Threads auf einen Slot, in dem du wieder dekrementierst.
    Das current-Thread sollte sowieso als Variable in den jeweiligen Thread (wenn das denn überhaupt von Belang ist). Dazu musst du einen passenden Konstruktor anbieten - und damit fällt dein statisches Thread-Array flach (zu unflexibel und kompliziert). Programmiere C++ und verwende einen dynamischen Container, z.B. QVector<MyThread*>.

    Und - tata - du brauchst keine einzige globale Variable mehr, Mutex locken kannst du dir auch schenken.


Anmelden zum Antworten