Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.net  
   

Die mobilen Seiten von c++.net:
https://m.c-plusplus.net

  
C++ Forum :: Andere GUIs - Qt, GTK+, wxWidgets ::  QThread richtig einsetzen  
Gehen Sie zu Seite Zurück  1, 2, 3, 4, 5, 6  Weiter
  Zeige alle Beiträge auf einer Seite
Auf Beitrag antworten
Autor Nachricht
Schlangenmensch
Mitglied

Benutzerprofil
Anmeldungsdatum: 28.11.2008
Beiträge: 353
Beitrag Schlangenmensch Mitglied 13:53:19 01.06.2017   Titel:              Zitieren

Saheb schrieb:

Warum ist nicht zu empfehlen beim Threadanwendung von QThread zu erben und somit wird die run() Methode überschrieben?


Um aus dem, von partsoft angegebenen Blog zu zitieren:

Zitat:

QThread was designed and is intended to be used as an interface or a control point to an operating system thread, not as a place to put code that you want to run in a thread. We object-oriented programmers subclass because we want to extend or specialize the base class functionality. [...]


tl;dr: Weil es dafür nicht entwickelt worden ist.
Saheb
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.11.2016
Beiträge: 116
Beitrag Saheb Mitglied 09:30:05 02.06.2017   Titel:   QThread richtig einsetzen            Zitieren

Hallo,

wenn ich folgende habe:
Header File:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
class QTcpSocket;
 
class CAgilentLan : public QThread
{
 
public:
 
    typedef enum
    {
        enRspTimeout = -2,
        enRspOffline,
        enRspOK,
        enRspError
    } t_enRspType ;
 
 
    CAgilentLan(QString strIpAdress_p, int iTimeout_p, bool boSimulate_p=false, bool boDebug_p=false);
    ~CAgilentLan();
 
    // High-Level Funktionen
    QByteArray ExecuteGetScreenshot(void);
    void ExecuteSaveScreenshot(QString &strPathFileName_p, const char *strFormat_p);
    void ExecuteSettingsSave(unsigned char ucRegisterNo_p);
    void ExecuteSettingsRecall(unsigned char ucRegisterNo_p);
    double ExecuteQuickMeasure(unsigned char ucChannel_p, char *pchType_p);
    double ExecuteStatMeasure(char *pchType_p, bool boTrigger_p);
    void ExecuteResetMeasurementStatistics(void);
 
    bool Open(const QString &strIpAdress_p, const int iTimeout_p);
    bool Close(const int iTimeout_p);
    t_enRspType Execute(const char *strCmd_p, const int iWaitResponse_p, const int iTimeout_p, const int iRspDelayed_p);
    QByteArray GetLastResponse(void);
 
    t_enRspType ExecuteSimulated(const char *strCmd_p);
    QString GetAgilentIdentifikation();
 
    ...
 
protected:
    void run();
 
private:
    bool m_boDebug;
    bool m_boSimulate;
   
    QMutex m_MtxProcess;
    QMutex m_MtxResponse;
 
    QWaitCondition m_WaitCondProcess;
    QByteArray m_ByteArrayWrite;
    QByteArray m_ByteArrayRead;
 
    QByteArray m_IDN_AgilentIdentification;
   
    //Hilfsvariable
    double m_SDDevPeriodeA ;
    double m_SDDevDCA;
    double m_SDDevDCB;
    double m_SDDevWidthZ;
 
    double m_OZiSDDevPeriodeA;
    double m_OZiSDDevDCA;
    double m_OZiSDDevDCB;
    double m_OZiSDDevWidthZ;
 
    double m_OZiMeanPeriodeA;
    double m_OZiMeanDCA;
    double m_OZiMeanDCB;
    double m_OZiMeanWidthZ;
   
    QByteArray m_ByteSTDD;
    QByteArray m_ByteMean;
    QStringList m_ListSTDDev;
    QStringList m_ListMean;
 
    QTcpSocket *m_pTcpSctCtrl;
   
    QString m_strCtrlIP;
    int m_iTimeoutClose;
    int m_iTimeout;
    int m_iResponseDelayed;
    int m_iWaitResponse;
 
    t_enRspType m_enRetVal;
};

Cpp File:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
CAgilentLan::CAgilentLan(QString strIpAdress_p, int iTimeout_p, bool boSimulate_p, bool boDebug_p):m_SDDevPeriodeA(0), m_SDDevDCA(0),m_SDDevDCB(0),m_SDDevWidthZ(0)
{
//  boSimulate_p = false;
   
    m_boDebug = boDebug_p;
    m_boSimulate = boSimulate_p;
 
    m_enRetVal = enRspOffline;
    m_strCtrlIP = QString("");
    m_iTimeout = 0;
    m_iTimeoutClose = iTimeout_p;
    if (this->Execute("CreateObject", 0, 0, 0) != enRspOK)
    {
        throw(QString("Error AgilentLan.CPP/Constructor TcpSocket Create memory error"));
    }
 
    this->Open(strIpAdress_p, iTimeout_p);
}
 
CAgilentLan::~CAgilentLan()
{
    while(isRunning());
 
    this->Close(m_iTimeoutClose);
 
    while(isRunning());
   
    if (this->Execute("DeleteObject", 0, 0, 0) != enRspOK)
    {
        throw(QString("Error AgilentLan.CPP/Destructor TcpSocket Delete memory error"));
    }
 
   
    while(isRunning());
}
bool CAgilentLan::Open(const QString &strCtrlIP_p, const int iTimeout_p)
{
    bool boRet_l = true;
 
    m_strCtrlIP = strCtrlIP_p;
       
    if (this->Execute("OpenConnection", 0, iTimeout_p, 0) != enRspOK)
    {
        throw(QString("Error AgilentLan.CPP/Open TcpSocket Open Connection error"));
    }
   
    if (m_boDebug)
    {
        throw(QString("Tcp Socket is open"));
    }
 
    return boRet_l;
}
 
bool CAgilentLan::Close(const int iTimeout_p)
{
    bool boRet_l = true;
 
    while(isRunning());
 
    if (this->Execute("CloseConnection", 0, iTimeout_p, 0) != enRspOK)
    {
        throw(QString("Error AgilentLan.CPP/Close Connection error"));
    }
   
    if (m_boDebug)
    {
        throw(QString("Tcp Socket is closed"));
    }
 
    while(isRunning());
 
    return boRet_l;
}
 
 
CAgilentLan::t_enRspType CAgilentLan::Execute(const char *strCmd_p, const int iWaitResponse_p, const int iTimeout_p, const int iRspDelayed_p)
{
    CAgilentLan::t_enRspType enRetVal_l = enRspOffline;
 
    if (!isRunning())
    {
        m_ByteArrayRead.clear();
 
        m_ByteArrayWrite.clear();
        m_ByteArrayWrite.append(strCmd_p);
       
        m_iWaitResponse = iWaitResponse_p;
        m_iTimeout = iTimeout_p;
        m_iResponseDelayed = iRspDelayed_p;
 
        start();
 
        m_MtxProcess.lock();
        m_WaitCondProcess.wait(&m_MtxProcess,-1);
        m_MtxProcess.unlock();
   
        enRetVal_l = this->m_enRetVal;
    }
    else
    {
        enRetVal_l = enRspError;
    }
   
    while(isRunning());
   
    return enRetVal_l;
}
 
QByteArray CAgilentLan::GetLastResponse(void)
{
    QByteArray ay_l;
 
    m_MtxResponse.lock();
    ay_l = m_ByteArrayRead;
    m_MtxResponse.unlock();
 
    return ay_l;
}
void CAgilentLan::run()
{
    bool boRun_l = true;
    bool boSent_l = false;
 
    const char *pStrCmd_l = NULL;
    const char *pStrRsp_l = NULL;
 
    m_enRetVal = enRspError;
 
    if (strcmp(m_ByteArrayWrite.data(),"CreateObject")==0)
    {
        if (this->m_boSimulate == true)
        {
            m_enRetVal = enRspOK;
        }
        else
        {
            m_pTcpSctCtrl = (QTcpSocket *)new QTcpSocket;
            if (m_pTcpSctCtrl != NULL)
            {
                m_enRetVal = enRspOK;
            }
        }
 
        boRun_l = false;
    }
 
    if (strcmp(m_ByteArrayWrite.data(),"DeleteObject")==0)
    {
        if (this->m_boSimulate == true)
        {
        }
        else
        {
            if (m_pTcpSctCtrl != NULL)
            {
                delete m_pTcpSctCtrl;
            }
        }
 
        m_enRetVal = enRspOK;
        boRun_l = false;
    }
 
    if (strcmp(m_ByteArrayWrite.data(),"OpenConnection")==0)
    {
        if (this->m_boSimulate == true)
        {
            m_enRetVal = enRspOK;
        }
        else
        {
            m_pTcpSctCtrl->connectToHost(m_strCtrlIP,5025);
            if (m_pTcpSctCtrl->waitForConnected(m_iTimeout) == true)
            {
                m_enRetVal = enRspOK;
            }
        }
       
        boRun_l = false;
    }
 
    if (strcmp(m_ByteArrayWrite.data(),"CloseConnection")==0)
    {
        if (this->m_boSimulate == true)
        {
            m_enRetVal = enRspOK;
        }
        else
        {
            m_pTcpSctCtrl->disconnectFromHost();
            if ((m_pTcpSctCtrl->state() == QAbstractSocket::UnconnectedState) || (m_pTcpSctCtrl->waitForDisconnected(m_iTimeout)))
            {
                m_enRetVal = enRspOK;
            }
        }
       
        boRun_l = false;
    }
 
    int iTimeout_l = m_iTimeout;
   
    while (boRun_l && (!this->m_boSimulate))
    {
        if (boSent_l == false)
        {
            boSent_l = true;
            // Kommando absetzen
            m_pTcpSctCtrl->write(m_ByteArrayWrite.data(),m_ByteArrayWrite.size());
            // Auf Antwort warten
            if (m_iWaitResponse >= 0)
            {
                QThread::msleep(m_iWaitResponse);
            }
            else
            {
                boRun_l = false;
            }
        }
       
        // Anwort auf Kommando abwarten
        if ((m_pTcpSctCtrl->bytesAvailable() > 0) && (boRun_l == true))
        {
            m_MtxResponse.lock();
 
            m_ByteArrayRead.append(m_pTcpSctCtrl->readAll());
           
            if (m_boDebug)
            {
                throw(QString(m_ByteArrayRead.data()));
            }
 
            m_MtxResponse.unlock();
 
            iTimeout_l = m_iTimeout;
//          iTimeout_l = m_iWaitResponse;
        }
        else
        {
            if (m_pTcpSctCtrl->waitForReadyRead(iTimeout_l) == false)
            {
                m_MtxResponse.lock();
 
                if (m_ByteArrayRead.size() == 0)
                {
                    if (m_boDebug)
                    {
                        throw(QString("AgilentLan Timeout"));
                    }
                    m_enRetVal = enRspTimeout;
                }
                else
                {
                    m_enRetVal = enRspOK;
                }
 
                m_MtxResponse.unlock();
               
                boRun_l = false;                   
            }
        }
    }
   
    QThread::msleep(m_iResponseDelayed);
   
    QMutexLocker locker(&m_MtxProcess);
 
    m_WaitCondProcess.wakeOne();
 
}

Diese Klasse möchte ich gerne umschreiben und zwar nach der vorgeschlagen "Qthread richtig einsetzen".
Das heisst ich muss eine neue Klasse z.B Work erstellen richtig?
Schlangenmensch
Mitglied

Benutzerprofil
Anmeldungsdatum: 28.11.2008
Beiträge: 353
Beitrag Schlangenmensch Mitglied 09:58:24 02.06.2017   Titel:              Zitieren

Du musst nicht unbedingt eine neue Klasse erstellen.

Du könntest zum Beispiel deine Klasse nicht von QThread erben lassen, sondern von QObject.
Die run() Methode raus nehmen, bzw. umbenennen und alle Funktionsaufrufe, bei denen du QThread Funktionen aufrufst raus nehmen (bzw. umschreiben).

Aber: Bevor du damit anfängst, überleg dir erst mal, welche Aufgabe du genau parallelisieren möchtest, warum diese Aufgabe parallel laufen soll, wie viele parallele Tasks du zulassen möchtest usw.

Außerdem ist es dann vlt eine Überlegung wert, ob du das nicht mit Futures und Promises realisieren kannst (Ein paar Erklärungen dazu: QT: http://blog.qt.io/blog/2017/04/18/multithreaded-programming-future-promise/ Boost: https://theboostcpplibraries.com/boost.thread-futures-and-promises) Das würde dir die low level Thread Erstellung abnehmen.
Saheb
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.11.2016
Beiträge: 116
Beitrag Saheb Mitglied 11:08:18 02.06.2017   Titel:   QThread richtig einsetzen            Zitieren

Schlangenmensch schrieb:

Du könntest zum Beispiel deine Klasse nicht von QThread erben lassen, sondern von QObject.

Okay
Das ist schon klar.

Schlangenmensch schrieb:

Die run() Methode raus nehmen, bzw. umbenennen und alle Funktionsaufrufe, bei denen du QThread Funktionen aufrufst raus nehmen (bzw. umschreiben).


Die run() Methode nenne ich um zu einen SLOT Methode richtig?


Zuletzt bearbeitet von Saheb am 11:09:26 02.06.2017, insgesamt 1-mal bearbeitet
Schlangenmensch
Mitglied

Benutzerprofil
Anmeldungsdatum: 28.11.2008
Beiträge: 353
Beitrag Schlangenmensch Mitglied 15:53:20 02.06.2017   Titel:              Zitieren

Ja, ich glaube du meinst das richtige. Du benennst die Methode um und deklarierst die als SLOT.

C++:
public slots:
   void doAnything();
Saheb
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.11.2016
Beiträge: 116
Beitrag Saheb Mitglied 10:07:00 28.06.2017   Titel:   QThread richtig einsetzen            Zitieren

Kannst du bitte mich auf die Sprünge helfen?
Ich habe es so angefangen:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class QTcpSocket;
 
class CAgilentLan : public QObject
{
    Q_OBJECT
 
public:
 ...
    CAgilentLan(QString strIpAdress_p, int iTimeout_p, bool boSimulate_p=false, bool boDebug_p=false);
    ~CAgilentLan();
 
...
    t_enRspType Execute(const char *strCmd_p, const int iWaitResponse_p, const int iTimeout_p, const int iRspDelayed_p);
 ..
 
public slots:
    void AgilentStart();
 
 
};


Die run() Methode umbenannt und zu einen Slot deklariert.
Mir ist dann nicht ganz klar wie soll ich die restlichen Methoden zu SLOT und SIGNAL einbinden kann?

In der alte Version was diese Methode :
C++:
t_enRspType Execute(const char *strCmd_p, const int iWaitResponse_p, const int iTimeout_p, const int iRspDelayed_p);

Zentral.

Das heisst jede aufruf diese Methode verusacht eine automatische Aufruf der
C++:
run()  
Methode.
Ich will weiterhin dieses Ablauf beibehalten damit die Änderung minimal bleibt.
Schlangenmensch
Mitglied

Benutzerprofil
Anmeldungsdatum: 28.11.2008
Beiträge: 353
Beitrag Schlangenmensch Mitglied 13:43:28 28.06.2017   Titel:              Zitieren

Hi,

vielleicht hilft dir die Seite: https://wiki.qt.io/QThreads_general_usage weiter.

Kurz zusammengefasst, an der Stelle, an der du CAgilentLan erzeugst und aufrufst muss du einen QThread erzeugen, mit moveToThread das Objekt in den Thread "schieben" und dann eben die Verbindung zwischen Signal und Slot herstellen.

Also ungetestet hast du dann irgendwo sowas

C++:
QThread* thread = new QThread;
CAgilentLan* worker = new CAgilentLan(/*Argumente nicht vergessen */);
worker->moveToThread(thread);
connect(thread, SIGNAL (started()), worker, SLOT (AgilentStart()));
thread->start();


Was hier noch fehlt ist das warten auf Beendigung des Threads (z.B. über ein Signal) und das löschen des Threads und CAgilentLan. Hierfür stellt QT für QObjects die Funktion QObject::deleteLater() bereit.
Saheb
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.11.2016
Beiträge: 116
Beitrag Saheb Mitglied 16:22:45 28.06.2017   Titel:   QThread richtig einsetzen            Zitieren

Hallo,

vielen dank für die Antwort.

Ich habe es noch eine Frage:

Schlangenmensch schrieb:


an der Stelle, an der du CAgilentLan erzeugst und aufrufst muss du einen QThread erzeugen....


Diesem satz habe ich nicht genau verstanden.

Bei jeden aufruf dieses Object CAgilentLan muss ich bei der betroffene Class in der Konstruktor sowas schreiben:

C++:
QThread* thread = new QThread;
CAgilentLan* worker = new CAgilentLan(/*Argumente nicht vergessen */);
worker->moveToThread(thread);
connect(thread, SIGNAL (started()), worker, SLOT (AgilentStart()));
thread->start();

oder verstehe ich das falsch?

Sorry noch mal
Schlangenmensch
Mitglied

Benutzerprofil
Anmeldungsdatum: 28.11.2008
Beiträge: 353
Beitrag Schlangenmensch Mitglied 09:01:12 29.06.2017   Titel:              Zitieren

An wie vielen Stellen hast du das denn?

Jedes mal, wenn du ein Objekt der Klasse CAgilentLan in einem extra Thread ausführen möchtest, benötigst du sowas in der Richtung.

Das muss nicht im Konstruktor sein.

Die Frage, die sich mir nach wie vor stellt ist, was genau willst du parallel ausführen.

Willst du mehrmals CAgilentLan::AgilentStart() parallel ausführen (wenn ich mich richtig erinnere gabs da Netzwerkverbungen)? Oder was ist deine Idee hinter der Parallelisierung.

Edit: Zu früh um richtig zu schreiben.


Zuletzt bearbeitet von Schlangenmensch am 09:02:09 29.06.2017, insgesamt 1-mal bearbeitet
Saheb
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.11.2016
Beiträge: 116
Beitrag Saheb Mitglied 10:03:11 29.06.2017   Titel:   QThread richtig einsetzen            Zitieren

Schlangenmensch schrieb:
An wie vielen Stellen hast du das denn?

Bei eine Klasse habe ich das in mehreren Stellen (15 mal).

Jedes mal, wenn du ein Objekt der Klasse CAgilentLan in einem extra Thread ausführen möchtest, benötigst du sowas in der Richtung.

Das muss nicht im Konstruktor sein.
[quote="Schlangenmensch"
Die Frage, die sich mir nach wie vor stellt ist, was genau willst du parallel ausführen.
[/quote]
Während es mit der Agilent kommuniziert ist, müssen die anderen Thread warten.
Schlangenmensch schrieb:

Willst du mehrmals CAgilentLan::AgilentStart() parallel ausführen (wenn ich mich richtig erinnere gabs da Netzwerkverbungen)? Oder was ist deine Idee hinter der Parallelisierung.


Nein Parallesieren möchte ich das nicht.
Mir ist wichtig, dass die Threads synchronisiert sind.

Was ich eigentlich für die Zukunft habe, ist der jetzigen Stand der CAgilentLan class zu erweitern in dem ich die VISA "https://en.wikipedia.org/wiki/Virtual_Instrument_Software_Architecture" Standard zu benutzen.
Grund für diese Umstieg: Der jetzigen Stand dauert sehr lange, wenn es stets eine neue Verbindug aufgebaut ist.
C++ Forum :: Andere GUIs - Qt, GTK+, wxWidgets ::  QThread richtig einsetzen  
Gehen Sie zu Seite Zurück  1, 2, 3, 4, 5, 6  Weiter
Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.net ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info und www.c-plusplus.net enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.