ã¿ãªããããã«ã¡ã¯ïŒ
ã©ãããããããVS2009ã®WinXPã®Qt 5.1.1ã§éäžçãªä¿¡å·äº€æãè¡ããã«ãã¹ã¬ããã¢ããªã±ãŒã·ã§ã³ãå®è£
ããå¿
èŠããããŸããã ç§ã¯
SchleeãåããQThreadããã¯ã©ã¹ãç¶æ¿ããå¿
èŠãããããšã圌ããå·®ãåŒããŸããã 念ã®ããã
Qtã®ããã¥ã¡ã³ãã調ã¹ãŸãããã¯ã©ã¹ãç¶æ¿ããQThreadã«å察ãã人ã¯ããŸããã§ããã ããŠ-泚æã¯å®äºã§ãïŒ ç§ã¯ãããå§ããŸã-ããã¯ããŸãããããã§ãããã©ããããããããã§ã¯ãããŸãã...ç§ã¯ãããã°ã¢ãŒãã§è¿œè·¡ãå§ããŸã-ãããŠæªéã¯ããã§äœãèµ·ãã£ãŠããã®ãç¥ã£ãŠããŸãïŒ ã·ã°ãã«ãçµäºããã«çµäºããåŸãäœããã®çç±ã§æ²ãã£ãŠå¥ã®ã¹ããªãŒã ããåºãŸãã äžèšã§èšãã°ãå®å
šãªæ··ä¹±ïŒ ç§ã¯åŸ¹åºçã«ã°ãŒã°ã«ã§èª¿ã¹ãŠããããã¯ãç解ããªããã°ãªããŸããã§ããïŒ
ããã®èšäºã
ãã ããããŠ
ããã®èšäº
ãç§ãå©ããŠãããŸããïŒã ãã®çµæãC ++ïŒãŸãã¯ãããã®éå±€å
šäœïŒã§ã¯ã©ã¹ãã³ãã¬ãŒããäœæããŸãããããã«ãããæ£ããå®å®ããŠåäœããå¥ã®ã¹ã¬ããã«ååšããã¯ã©ã¹ã®ïŒæ¯èŒçïŒå°ããªã³ãŒããèšè¿°ã§ããŸããã
UpdïŒ ã³ã¡ã³ãã§åœŒãã¯ããè¯ãã¢ãããŒããææ¡ããŸãã-ç§ã¯ãããæ°ããèšäºã§èª¬æããŸãã ã
äœã欲ãã
ç§ã¯éåžžã«æçœãªããšãæ±ããŠåªåããŸããïŒ
- ãã¹ãŠã®æ å
ã®äžã§C ++ã¯ã©ã¹ã䜿çšããŸããã€ãŸããã¹ããªãŒã ã®äœææã«ã³ã³ã¹ãã©ã¯ã¿ãŒãåŒã³åºãããç Žæ£åã«ãã¹ãã©ã¯ã¿ãåŒã³åºãããŸãã
- ãã¹ãŠã®æ å
ã§Qtã®æ©èœã䜿çšããŸã-ããªãã¡ãä¿¡å·ã¹ãããæ¥ç¶ãã€ãã³ããªã©ã
- å¿
èŠã«å¿ããŠ-äœæãšäœæ¥ã®ããã»ã¹ãå¶åŸ¡-ãããŒã®åªå
é äœãäœæ¥ã®éå§ã«é¢ããã¹ããããç·æ¥å®äºã«é¢ããä¿¡å·ã
- æå°éã®èœæžããšæ倧éã®æçãã
ç§ã¯æ¬¡ã®ãããªãã®ãåŸãŸããïŒ
class SomeJob: public QObject { Q_OBJECT public: SomeJob () { /* ... */ } // ~SomeJob () { /* ... */ } // signals: void finished (); // public slots: void to_terminate () { /* ... */ } // }; ... ThreadedObject<SomeJob> thr; // - thr.start (); //
çŸäººïŒ
ã©ã®ããã«è¡åããã
Qt 5.1ã§ã¯ãäœã¬ãã«ã®QThreadã¯ã©ã¹ã¯ç§ãã¡ã®ç®çã®ããã®ãã®ã§ãã 圌ã«ã€ããŠ
次ã®ããã«èšãããŠããŸãïŒãQThreadã¯ã©ã¹ã¯ããã©ãããã©ãŒã ã«äŸåããªãæ¹æ³ã§ã¹ã¬ããã管çããæ©èœãæäŸããŸããã Schleeã«ã¯çŽ æŽãããæ¬ããããŸãããããã«éåžžã«çŽããããã¹ã¬ããã®äŸããããŸããQThreadã¯ã©ã¹ã
ç¶æ¿ããrunïŒïŒã¡ãœããããªãŒããŒã©ã€ããããã®äžã§äœæ¥ãè¡ãããšããå§ãããŸãã ããã¯ããéå§ãæ©èœã®å®è¡ãå®äºãã®ã¹ã¿ã€ã«ã®ã¿ã¹ã¯ã«ã¯æªãããšã§ã¯ãããŸããããããè€éãªã±ãŒã¹ã§ã¯æ確ã«åãå
¥ããããŸããã
äžè¬çã«ãç§
ã¯ããã
èããŠèªãã ãšããŠãç¡é§ã§ãããã«ããã¥ã¡ã³ããæãäžããå¿
èŠããããŸããã ã¡ãªã¿ã«ãè¯ãäŸããããŸãã æ£ãããã¹ã瀺ããŠããŸãïŒ
QObject :: moveToThreadïŒQThread * threadïŒé¢æ° ããã®ãªããžã§ã¯ããšãã®ãã¹ãŠã®ç¥å
ã®
芪åæ§ ïŒé¡äŒŒæ§-è±èªã®èŠªåæ§ïŒãã¹ã¬ããthreadã«è»¢éããŸãã
ãããã£ãŠãæåã®è¿äŒŒã§ã¯ãåé¡ã®è§£æ±ºçã¯æ¬¡ã®ãšããã§ãã
- ã¹ã¬ããäœæ-QThreadã¯ã©ã¹ã
- ãªããžã§ã¯ããäœæãããããæ°ããã¹ããªãŒã ã«è»¢éããŸãã
- ä¿¡å·ã¹ãããéä¿¡ã®èšçœ®ã
- ç¹å®ã®åªå
床ã§ã¹ããªãŒã ãéå§ããŸãã
ãã¹ãŠããŸãããããã§ãããèŠããŠããŸããïŒ -äœæããããªããžã§ã¯ãã®ã³ã³ã¹ãã©ã¯ã¿ãŒã
æ°ããã¹ã¬ããã§å®è¡
ãããã ãããè¡ã
ã«ã¯ãã¹ã¬ããã®éå§
åŸã«éå§ããå¿
èŠããããŸãã æåã«ãªããžã§ã¯ããäœæãã次ã«ã¹ããªãŒã ãäœæã§ããŸãã ãã ãããªããžã§ã¯ãã®ã³ã³ã¹ãã©ã¯ã¿ãŒã«ãã£ãŠäœæããããã¹ãŠã®ãã®ã¯ãæ°ããã¹ã¬ããã§ã¯ãªãã
çŸåšã®ã¹ã¬ããã®ã¹ã¿ãã¯ïŒããŒãïŒã«é
眮ãããŸãã ãã®ãšã³ãããŒã®ãã¹ãŠãæ°ããã¹ã¬ããã«ããŸã転éããå€ãã¹ã¬ããã§åé€ããããšã¯ã§ããŸããã...æ°ããã¹ã¬ããã§æ¢ã«ã³ã³ã¹ãã©ã¯ã¿ãŒãåŒã³åºãæ¹ãç°¡åã§ãã ãããã£ãŠãããã«åé¡çªå·1ããããŸãã 決ããå¿
èŠããããŸãã
次ã«ãåé¡çªå·2ããããŸããã QObjectããç¶æ¿ããçŽ æµãªãã³ãã¬ãŒããäœæããŸãããããã¯ãä¿¡å·ã¹ãããéä¿¡ã«å¿
èŠã§ãã ãããŠã
ãã€ã¯ãæµ®äžããŸããããMOCã§ã¯ãC ++ã®ãã¹ãŠã®æ©èœã䜿çšã§ããŸããã äž»ãªåé¡ã¯ã
ã¯ã©ã¹ãã³ãã¬ãŒãã«ã·ã°ãã«ãŸãã¯ã¹ããããå«ããããšãã§ããªãããšã§ãã ïŒ@ïŒ*ïŒ
ãã ãããã®ãããã¯ãå
æããŸããã
ç§ã¯æ¬¡ã®ã¯ã©ã¹ãæãã€ããïŒ
- ãã€ãã£ãã¯ã©ã¹ã¯Tã§ãã
- ãªããžã§ã¯ãäœæã¯ã©ã¹-CreatorBaseïŒQObjectã®åå«ïŒããããŸãã ä»®æ³ã¡ãœãããåŒã³åºãããšã«ããã圌ã¯ã¹ãããã«æ°ãããªããžã§ã¯ããäœæãããã®ã¢ãã¬ã¹ãã·ã°ãã«ã§éä¿¡ããŸãã
- äœæè
ã¯ã©ã¹-Creator <T>ïŒCreatorBaseã®åå«ïŒã®ãã³ãã¬ãŒãå®è£
ããããŸãã ç¹å®ã®ã¿ã€ãã®ãªããžã§ã¯ããäœæããã¡ãœãããå®è£
ããŸãã
- æ°ããã¹ã¬ãããäœæããThreadedObjectBaseã¯ã©ã¹ïŒQObjectã®åå«ïŒããããŸãã CreatorBaseäœæè
ãåãåããå¿
èŠãªä¿¡å·ã¹ãããéä¿¡ã確ç«ããŸãã
- ãŠãŒã¶ãŒã¯ãªããžã§ã¯ãã®ãã³ãã¬ãŒãã¹ãã¬ãŒãžã¯ã©ã¹ã䜿çšããThreadedObject <T>ïŒThreadedObjectBaseã®åå«ïŒãã¹ããªãŒã ããŸãã æ°ãããªããžã§ã¯ãã®äœæãåŒã³åºãã*ããã³->æŒç®åãããã³äœæããããªããžã§ã¯ãã®ã¿ã€ããã€ã³ã¿ãŒããªãŒããŒããŒãããŸãã
- ãŠãŒã¶ãŒãã¯ã©ã¹ãäœæãïŒQObjectã®åå«ã«ãªãããšãã§ããŸãïŒããªãã·ã§ã³ã§ãclass finished workããšãwork of interruptionãã®ã·ã°ãã«ãå®è£
ãããªããžã§ã¯ãã®é
延åé€ãèšå®ã§ããŸã ã
ã¢ã¯ã·ã§ã³ã®ã·ãŒã±ã³ã¹ã¯åçŽã§ããããšãå€æããŸããã
- ãªããžã§ã¯ããšThreadedObjectã¹ããªãŒã ã®ã¹ãã¬ãŒãžã¯ã©ã¹ã䜿çšãããŸãã
- 圌ã¯ãäœæè
ã®äœæè
ãšæ°ããã¹ã¬ããã®QThreadãªããžã§ã¯ããäœæããŸãã
- ãªããžã§ã¯ãã®äœæè
ãæ°ããã¹ã¬ããã«è»¢éãããŸãã
- ä¿¡å·ã¹ãããéä¿¡ã確ç«ãããŸãã
- æ°ããäœæãããã¹ã¬ããã¯ãå¿
èŠãªåªå
床ã§å§ãŸããŸãã
- äœæãããã¹ã¬ããã«ã«ã¹ã¿ã ã¯ã©ã¹TãäœæãããŸãã
- ThreadedObjectBaseã¯ãsetObjectïŒvoid * ObjïŒã¹ãããã䜿çšããŠããã«ã€ããŠåŠç¿ãããªããžã§ã¯ãã®ã¢ãã¬ã¹ãèšæ¶ããä¿¡å·objectIsReadyïŒïŒã䜿çšããŠããã«ã€ããŠäžçã«éç¥ããŸãã
- ããããã¹ãŠã®ã¢ã¯ã·ã§ã³ã®æ£åžžçµäºã«ã€ããŠã¯ãbool ThreadedObject <T> :: objectIsCreatedïŒvoidïŒconstãåç
§ããŠãã ããã
å®è£
äœæãããã¯ã©ã¹ã®ã³ãŒããèæ
®ããŠãã ããïŒãã¹ãŠãç»é¢ã«åãŸãããã«ãã³ã¡ã³ããåé€ããŸããïŒã
ãªããžã§ã¯ãäœæè
ïŒ
class CreatorBase: public QObject { Q_OBJECT void *_obj; protected: virtual void *Allocation (void) = 0; public slots: void allocate (void) { emit setObject (Allocation ()); } signals: void setObject (void *Obj); }; template <class T> class Creator: public CreatorBase { protected: void *Allocation (void) { return reinterpret_cast <void*> (new T); } };
ããã§ã¯ãã¹ãŠãæçœã§ããCreatorBaseã¯ãªãšãŒã¿ãŒã®åºæ¬ã¯ã©ã¹ã«ã¯ãæ°ããã¢ã¯ãã£ããªã¹ã¬ããã§èµ·åãããallocateïŒïŒã¹ãããããããŸãã ã·ã°ãã«setObjectïŒvoid * ObjïŒãåŒã³åºããŸããããã¯ãåvoid * Creator <T> :: AllocationïŒïŒã§äœæããããªããžã§ã¯ãã®ã¢ãã¬ã¹ãæž¡ããŸãã
åºåºã¯ã©ã¹ThreadedObjectBaseã¯æ¬¡ã®ãšããã§ãã
class ThreadedObjectBase: public QObject { Q_OBJECT protected: QThread *_thread; virtual void SetObjectPointer (void *Ptr) = 0; ThreadedObjectBase (QObject *parent = 0): QObject (parent), _thread (0) {} void starting (CreatorBase *Creator, QThread::Priority Priority = QThread::InheritPriority, bool ToDeleteLaterThread = true) { bool res; _thread = new QThread; Creator->moveToThread (_thread); res = connect (_thread, SIGNAL (started ()), Creator, SLOT (allocate ())); Q_ASSERT_X (res, "connect", "connection is not established"); res = connect (Creator, SIGNAL (setObject (void*)), this, SLOT (setObject (void*))); Q_ASSERT_X (res, "connect", "connection is not established"); if (ToDeleteLaterThread) { res = connect (_thread, SIGNAL (finished ()), _thread, SLOT (deleteLater ())); Q_ASSERT_X (res, "connect", "connection is not established"); } _thread->start (Priority); } public: virtual ~ThreadedObjectBase (void) { } QThread *thread (void) { return _thread; } const QThread *cthread (void) const { return _thread; } signals: void objectIsReady (void); private slots: void setObject (void *Obj) { SetObjectPointer (Obj); emit objectIsReady (); } };
ããã§ã®äž»ãªæ¹æ³ã¯éå§äžã§ãã æå®ãããåªå
床ã§ã¹ã¬ãããäœæããŸãã èµ·åãããšã_threadã¹ã¬ããã¯
QThread :: startedïŒïŒã·ã°ãã«ãåŒã³åºããŸãã ãã®ä¿¡å·ãã¹ãããCreatorBase :: allocateïŒïŒã«é¢é£ä»ããŠãæ°ãããªããžã§ã¯ããäœæããŸãã ããã«ãããä¿¡å·CreatorBase :: setObjectïŒvoid *ïŒãçºçããŸããããã¯ãã¹ãããThreadedObjectBase :: setObjectïŒvoid * ObjïŒã§ååŸããŸãã ãã¹ãŠããªããžã§ã¯ããäœæããïŒããã«ã€ããŠä¿¡å·ThreadedObjectBase :: objectIsReadyïŒïŒãçºè¡ãããŸãïŒããªããžã§ã¯ããžã®ãã€ã³ã¿ãŒãåä¿¡ãããŸãã
ãŠãŒã¶ãŒãã¹ã¬ããã¯ã©ã¹ã®é
延åé€ïŒæãŸããïŒãèšå®ããå Žåãæ¥ç¶ã¯_thread
QThread :: finish ïŒïŒ ->
QObject :: deleteLaterïŒïŒå
ã§ç¢ºç«ãããŸãã
ãŸãããŠãŒã¶ãŒã¯ä¿¡å·ã®ååãèšå®ã§ããŸãïŒå€æ°_finished_signalã«æ ŒçŽãããŸãïŒã ãã®ã·ã°ãã«ã¯ãäœæããããªããžã§ã¯ãã®äœæ¥çµäºæã«åŒã³åºãããŸãã åæ§ã«ã_terminate_slotããã®ã¹ãããã¯ãã¹ã¬ããå²ã蟌ã¿ã·ã°ãã«ã«ãã£ãŠåŒã³åºãããŸãïŒãã ããã¹ã¬ããã¯å³åº§ã«åæ¢ããŸãããã¹ã¬ããïŒïŒ-> waitãåç
§ããŠãçµäºããã®ãåŸ
ã€ããšãã§ããŸã
-QThread :: waitãåç
§ïŒã
æåŸã«ããŠãŒã¶ãŒã«è¡šç€ºããããã³ãã¬ãŒãã¯ã©ã¹ïŒ
template <class T> class ThreadedObject: public ThreadedObjectBase { protected: T* _obj; Creator<T> _creator; const char *_finished_signal; const char *_terminate_slot; bool _to_delete_later_object; void SetObjectPointer (void *Ptr) { bool res; _obj = reinterpret_cast <T*> (Ptr); if (_finished_signal) { res = connect (_obj, _finished_signal, _thread, SLOT (quit ())); Q_ASSERT_X (res, "connect", "connection is not established"); } if (_terminate_slot) { res = connect (_thread, SIGNAL (finished ()), _obj, _terminate_slot); Q_ASSERT_X (res, "connect", "connection is not established"); } if (_to_delete_later_object && _finished_signal) { res = connect (_obj, _finished_signal, _obj, SLOT (deleteLater ())); Q_ASSERT_X (res, "connect", "connection is not established"); } } public: ThreadedObject (QObject *parent = 0): ThreadedObjectBase (parent), _obj (0) { } ~ThreadedObject (void) { } void start (const char *FinishedSignal = 0, const char *TerminateSlot = 0, QThread::Priority Priority = QThread::InheritPriority, bool ToDeleteLaterThread = true, bool ToDeleteLaterObject = true) { Creator<T> *creator = new Creator<T>; _finished_signal = FinishedSignal; _terminate_slot = TerminateSlot; _to_delete_later_object = ToDeleteLaterObject; starting (_creator, Priority, ToDeleteLaterThread); delete creator; } bool objectIsCreated (void) const { return _obj != 0; } T* ptr (void) { return reinterpret_cast <T*> (_obj); } const T* cptr (void) const { return reinterpret_cast <const T*> (_obj); }
ããã§ãã¡ã€ã³ã®ã¡ãœããã¯startã§ããããã¯ã·ã°ãã«ãšã¹ãããã®ååãèšæ¶ããã¡ãœããã®é
延åé€ãèšå®ããŸãã objectIsCreatedïŒïŒã¡ãœããã¯ããªããžã§ã¯ããæ¢ã«äœæãããŠããå Žåã«trueãè¿ããŸãã è€æ°ã®ãªãŒããŒããŒãã«ãããThreadedObject <T>ãã¹ããŒããã€ã³ã¿ãŒãšããŠäœ¿çšã§ããŸãã
ãããã®ã¯ã©ã¹ã䜿çšããç°¡åãªäŸã次ã«ç€ºããŸãã
ThreadedObject <Operation> _obj; QObject::connect (&_obj, SIGNAL (objectIsReady ()), this, SLOT (connectObject ())); _obj.start (SIGNAL (finished ()), SLOT (terminate ()), QThread::HighPriority);
å®éã®äŸã以äžã«æ·»ä»ããŸã-ã¡ã€ã³ã¹ã¬ããã«ãã¿ã³ãäœæãããŸãã intå€æ°ã¯ãæ°ããã¹ã¬ããã§äœæãããã¿ã€ããŒããã®ã·ã°ãã«ãšã¿ã€ããŒã€ãã³ããäœæãããŸãã ãããã®ã¿ã€ããŒã¯äž¡æ¹ãšãintå€æ°ã®å€ãæžãããŸã;ãŒãã«éãããšã
QCoreApplication :: quitïŒïŒã¹ããããåŒã³åºãããŸãã äžæ¹ãã¢ããªã±ãŒã·ã§ã³ãéãããšãã¹ã¬ãããåæ¢ããŸãã WinXPã§ãã¹ããããäŸã LinuxãMacOSãAndroidãããã³
ãã®ä»ã®ãµããŒããããŠãããã©ââãããã©ãŒã ã§ã®æåãããã¹ãã«ã€ããŠã®ã³ã¡ã³ããèããã
ã§ã ã
äŸ+ã¯ã©ã¹ThreadedObjectãã¡ã€ã«ïŒ
Main.cppãã¡ã€ã«ïŒ
#include <QtGui> #include <QtWidgets> #include <QtCore> #include "ThreadedObject.h" // ** // ** // ** class Operation: public QObject { Q_OBJECT int *Int; // QTimer _tmr; // int _int_timer; // public: Operation (void) { Int = new int (5); } // ~Operation (void) { if (Int) delete Int; } // signals: void addText(const QString &txt); // " " void finished (); // " " public slots: void terminate () // { killTimer (_int_timer); // _tmr.stop (); // delete Int; // Int = 0; // emit finished (); // } void doAction (void) // { bool res; emit addText (QString ("- %1 -"). arg (*Int)); res = QObject::connect (&_tmr, &QTimer::timeout, this, &Operation::timeout); Q_ASSERT_X (res, "connect", "connection is not established"); // _tmr.start (2000); // thread()->sleep (1); // 1 ... timeout (); // ... ... startTimer (2000); // ... } protected: void timerEvent (QTimerEvent *ev) { timeout (); } // private slots: void timeout (void) { if (!Int || !*Int) // ? return; // ... --*Int; // emit addText (QString ("- %1 -"). arg (*Int)); // if (!Int || !*Int) // ? emit finished (); // ... } }; // ** // ** , // ** class App: public QObject { Q_OBJECT ThreadedObject <Operation> _obj; // - QPushButton _btn; // protected: void timerEvent (QTimerEvent *ev) { bool res; // - killTimer (ev->timerId ()); // res = QObject::connect (&_obj, SIGNAL (objectIsReady ()), this, SLOT (connectObject ())); Q_ASSERT_X (res, "connect", "connection is not established"); // _obj.start (SIGNAL (finished ()), SLOT (terminate ()), QThread::HighPriority); // } private slots: void setText (const QString &txt) { _btn.setText (txt); } // void connectObject (void) // { bool res; // - res = QObject::connect (this, &App::finish, _obj, &Operation::terminate); Q_ASSERT_X (res, "connect", "connection is not established"); // res = QObject::connect (this, &App::startAction, _obj, &Operation::doAction); Q_ASSERT_X (res, "connect", "connection is not established"); // res = QObject::connect (_obj, &Operation::finished, this, &App::finish); Q_ASSERT_X (res, "connect", "connection is not established"); // res = QObject::connect (_obj, &Operation::addText, this, &App::setText); Q_ASSERT_X (res, "connect", "connection is not established"); // res = QObject::connect (&_btn, &QPushButton::clicked, _obj, &Operation::terminate); Q_ASSERT_X (res, "connect", "connection is not established"); // _btn.show (); // emit startAction (); // } public slots: void terminate (void) { emit finish (); } // signals: void startAction (void); // " " void finish (void); // " " }; // ** // ** // ** int main (int argc, char **argv) { QApplication app (argc, argv); // App a; // bool res; // a.startTimer (0); // res = QObject::connect (&a, SIGNAL (finish ()), &app, SLOT (quit ())); Q_ASSERT_X (res, "connect", "connection is not established"); // res = QObject::connect (&app, SIGNAL (lastWindowClosed ()), &a, SLOT (terminate ())); Q_ASSERT_X (res, "connect", "connection is not established"); // return app.exec(); // } #include "main.moc"