2011-02-04 14 views
12

İnsanın, yazılımı çalması için sipariş ettiği herhangi bir zamanda kesebileceği bir Git programı uygulamıyorum. Temel olarak, her an bir "En İyi Hareket" e sahip olan ve gelişmeye devam eden başka bir iş parçacığında çalışan bir algoritmam var.QThread sonsuz döngüsünü düzgün bir şekilde kesmek için

Soruma soru sormak istiyorum: Sonsuz döngüde bir iş parçacığı nasıl doğru şekilde keserim?

bir kaç şey denedik ve bunu yapmak için çözdüğünüz

:

class MyWorker : public QObject 
{ 
    Q_OBJECT 
public: 
    MyWorker(); 
    ~MyWorker(); 

public: 
    ThreadControl * getThreadControl(); 

public slots: 
    void work(); 

private: 
    void endOfComputation(); 

private: 
    ThreadControl * threadControl; 
} 

Bildirimi ben don't subclass QThread:

class ThreadControl : public QObject 
{ 
    Q_OBJECT 
public: 
    ThreadControl(); 

public: 
    bool getAbort(); 
    Parameter getParameter(); 
    void setParameter(Parameter & param); 

public slots: 
    void setAbort(bool b); 

private: 
    QMutex mutex; 
    bool abort; 
    Parameter param; 
}; 

Ve son olarak, sonsuz döngü bu şekilde kodlanmıştır: Eğeryılında, tahmin edebilirsiniz Sonra

void Myworker::work() 
{ 
    // ... 
    forever 
    { 
     abort = threadControl->getAbort(); 
     if(abort) 
     { 
      break; 
     } 
     // ... 
    } 
    endOfComputation(); 
} 

, 10, düzenli ben sadece ana iş parçacığı bir mantıksal değere bir işaretçi tutmak, Temelde ThreadControl::setAbort(true)

arayıp istediğinizde bunu geçiş. (Boolean, ThreadControl içinde kapsüllenir; böylece bir muteks ile düzgün şekilde kilitleyebilirim). Şimdiye kadar çok iyi, benim için çalıştı ... Ama bana iğrenç geliyor! Booleanlar için işaretçiler ses gibi geliyor ... kötü programlama bana ...

Sorun, web'deki belgelerin çoğunlukla (tamamen? için. Bir iş parçacığı kesiliyor değil, bu yüzden soruyorum: Daha iyi bir yolu var mı?

cevap

5

Bunu yapmak için iyi bir yöntem gibi görünüyor. Ayrıca, boost thread'un nasıl yapıldığına bir göz atabilirsiniz. İş parçacığını iptal etmek için istisnalar kullandığından, iş parçacığını interruption_point kullanarak çeşitli yerlerde kesmenize izin verir. Konuyu içeriden, onlar (diş başına) bir boolean kullanmak olduğunu düşünüyorum

void myFunction(){ 
    boost::this_thread::interruption_point(); 
} 

void Myworker::work() 
{ 
    // ... 
    try 
    { 
     forever 
     { 
      boost::this_thread::interruption_point(); 
      // do some work 
      boost::this_thread::interruption_point(); 
      // work again 
      myFunction(); // interruption might be triggered inside this function 
     } 
     endOfComputation(); 
    } 
    catch(boost::thread_interrupted const &){ 
     // The thread has been interrupted 
    } 
} 

boost::thread::interrupt() yöntemi çağrıldığında true olarak ayarlanır: kendi iplik modelini bu gibi iplik işlevi yazabilirsiniz kullanma.

DÜZENLEME

Amacım bu sorunu çözmüştür boost nasıl göstermektir. Tabii ki, bu QThread ile çalışmayacak. Ben de boost :: thread için geçiş yapmak istemiyorum. QThread ile

EDIT2 Hızlı uygulama:

void function(); 

class MyWorker : public QThread { 
public: 

    MyWorker() : m_isInterrupted(false) {} 

    class InterruptionException { 
    public: 
     InterruptionException(){} 
    }; 
    static void interruptionPoint(){ 
     MyWorker * myWorker = dynamic_cast<MyWorker*>(QThread::currentThread()); 
     if(myWorker){ 
      if(myWorker->m_isInterrupted){ 
       throw InterruptionException(); 
      } 
     } 
    } 

public slots: 
    void interrupt(){ 
     m_isInterrupted = true; 
    } 
    void work(){ 
     try { 
      while(true){ 
       MyWorker::interruptionPoint(); 
       function(); 
      } 
     } 
     catch(InterruptionException const &){ 

     } 
    } 

private: 
    bool m_isInterrupted; 
}; 

void function(){ 
    MyWorker::interruptionPoint(); 
} 
+1

boost iplik QThread ile çalışmıyor:

Ben de ile döngü değiştireceksiniz. insanlar qt genellikle kullanır çünkü bu bir qt gui uygulamasıdır. –

+0

Amacım, bu ileti dizisini kesmenin başka bir yolunu sağlamaktı. Örnek bir uygulama eklendi. – tibur

7

Ben bayrakları geçmek yerine uzman yöntemlerinin çeşit çağırarak çirkin görünüyor, ama gerçek hayatta bunu yapmanın en iyi yolu olduğunu biliyoruz. Uzmanlaşmış yöntemler genellikle çok tehlikelidir, örneğin bkz. QThread::terminate(). Bazı ortamlar kullanıma hazır bayrakları sağlar, böylece kendi Boole'larınızı, Thread.interrupt() ve Thread.interrupted() ile Java gibi eklemeniz gerekmez. Qt'nin böyle bir şeyi yoktur ve belki de bu iyidir çünkü kesintiye uğrama bazen Java'da karşı-sezgisel olarak çalışır. Örneğin, Thread.interrupted() ve Thread.isInterrupted() arasındaki farkı alın. Kesinlikle karşı sezgisel.Dokümanlara başvurmadıkça, farkın ne olduğunu tahmin edemezsiniz. Daha da kötüsü, bunlardan biri statik olduğundan, 'un fark olduğunu düşünebilirsiniz, ancak bu değil. Ayrıca, eski stil IO işlemleri Java'da kesilemez, ancak yeni tarzdaki NIO'lar da bu kadar mantıklı değil.

Bazen başka bir şey kullanarak bayraklardan kaçınabilirsiniz. Örneğin, bir iş parçacığı işlemek için öğelerin bir tür giriş kuyruğuna sahipse, hemen orada durması gerektiğini belirtmek için özel bir bitiş öğesi kullanabilirsiniz. Ancak bazen bunu koymak için uygun bir yer yoktur, boole bayrakları kullandığınızda budur.

Kodunuzu biraz optimize etmek için yapabileceğiniz tek şey, muteks kilitlemeyi uçucu bir boole değiştirmektir. Bu, bellek erişim düzenini garanti etmeyecektir, bu nedenle iş parçacığınız uçucu yazma çevresinde meydana gelen bir şeye bağlıysa, bu şekilde gitmemelisiniz. Ya da bunun yerine bellek engelleri ile bir QAtomicInt kullanabilirsiniz. Ancak, önemli bir performans etkisi yoksa, muteks kullanmak gayet iyi ve güvenlidir.

while (!threadControl->getAbort()) { 
    // ... 
+0

Java'nın Thread.interrupt() ve interrupted() 'ın karşı intitivitesine ilişkin bazı örneklere bağlantı verebilir misiniz? –

+1

@Josiah, herhangi bir _links_ düşünemiyorum, ama benim düzenleme bakın. –

+0

Teşekkürler. Bu yararlı bir gözlem! –

İlgili konular