2011-10-31 14 views
20

Bir iş parçacığı oluşturuyorum ve onu sonsuz bir döngüye koydum. valgrind ile kod kontrol ederken ben bellek sızıntıları olsun. İşte benim kodudur:Sonsuz bir döngüde olan bir pthread'i bu döngüden nasıl nasıl öldürebilirim?

#include <pthread.h> 
#include <time.h> 

void thread_do(void){ 
    while(1){} 
} 

int main(){ 
    pthread_t th; 
    pthread_create(&th, NULL, (void *)thread_do, NULL); 

    sleep(2); 
    /* I want to kill thread here */ 
    sleep(2); 
    return 0; 
} 

Yani bir iş parçacığı ana oluşturulur ve sadece thread_do() her zaman çalışır. içindeki ana sonra 2 saniye onu öldürmek için bir yol var mı? Hem pthread_detach(th) hem de pthread_cancel(th)'u denedim ama yine de sızıntı alıyorum.

+3

Pthreads'ın iptal edilmesi, iş parçacığının tahsis ettiği herhangi bir belleği temizleme şansı olmadığı anlamına gelir. –

+2

Tamam Bunu küresel bir 'keepalive = 1' yaparak çözdüm. Sonra ben (1) ile "while (keepalive)" arasında değiştim. Şimdi iş parçacığı öldürmek için sadece 0 ve voila değişken tutma değerini değiştirmek zorundayım! – Pithikos

cevap

32

... ama bu can iş parçacığının iptal türünü ertelenmiş yerine eşzamansız olarak ayarlamak için pthread_setcanceltype()'u kullanarak değiştirin. Bunu yapmak için, döngüyü başlatmadan önce, iş parçacığı işlevinin başlangıcına yakın pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); gibi bir şey ekleyeceksiniz. Daha sonra main() dan pthread_cancel(th) arayarak parçacığı sonlandırmak mümkün olacaktır.

Ancak, iş parçacığı bu şekilde (eşzamansız olsun veya olmasın) iptal etmenin, iş parçacığı işlevinde ayrılan kaynakları temizlemediğini unutmayın (bir yorumda Kevin tarafından belirtildiği gibi). temiz Bunu yapmak için, şunları yapabilirsiniz:

  • parçacığı
  • Eğer bir yol olduğundan emin olun (örneğin bir tampon tahsis etmek malloc() kullanarak) çıkışında önce temizlemek gerekiyor şey yapmaz emin olun iplik iplik iptal edildiğinde
  • Kullanım pthread_cleanup_push() ve pthread_cleanup_pop() kaynakları temizlemek için temizleme işleyicileri eklemek çıktıktan sonra başka bir yerde iş parçacığı sonra temizlemekten. İptali bir kaynak ayırmak ve temizleme işleyicisini eklemek arasında iptal edilebildiğinden, iptal türü eşzamansız ise bu durumun hala riskli olduğunu unutmayın.
  • kaçının pthread_cancel() kullanarak ve iplik (uzun süren döngüler kontrol edileceği) sonlandırmak için ne zaman belirlemek için bazı durumunu kontrol var. İş parçanız daha sonra fesihin kendisi için kontrol ettiği için, kontrolden sonra ne gerekiyorsa temizler. İplik değilse

    #include <pthread.h> 
    #include <unistd.h> 
    #include <errno.h> 
    
    /* Returns 1 (true) if the mutex is unlocked, which is the 
    * thread's signal to terminate. 
    */ 
    int needQuit(pthread_mutex_t *mtx) 
    { 
        switch(pthread_mutex_trylock(mtx)) { 
        case 0: /* if we got the lock, unlock and return 1 (true) */ 
         pthread_mutex_unlock(mtx); 
         return 1; 
        case EBUSY: /* return 0 (false) if the mutex was locked */ 
         return 0; 
        } 
        return 1; 
    } 
    
    /* Thread function, containing a loop that's infinite except that it checks for 
    * termination with needQuit() 
    */ 
    void *thread_do(void *arg) 
    { 
        pthread_mutex_t *mx = arg; 
        while(!needQuit(mx)) {} 
        return NULL; 
    } 
    
    int main(int argc, char *argv[]) 
    { 
        pthread_t th; 
        pthread_mutex_t mxq; /* mutex used as quit flag */ 
    
        /* init and lock the mutex before creating the thread. As long as the 
        mutex stays locked, the thread should keep running. A pointer to the 
        mutex is passed as the argument to the thread function. */ 
        pthread_mutex_init(&mxq,NULL); 
        pthread_mutex_lock(&mxq); 
        pthread_create(&th,NULL,thread_do,&mxq); 
    
        sleep(2); 
    
        /* unlock mxq to tell the thread to terminate, then join the thread */ 
        pthread_mutex_unlock(&mxq); 
        pthread_join(th,NULL); 
    
        sleep(2); 
        return 0; 
    } 
    

    : son seçeneği uygulanması

bir yolu döngü testlerinde kullanılacak bir bayrak gibi bir muteksi kullanın ve bir fonksiyonu sarılmış pthread_mutex_trylock() ile test etmektir müstakil (genellikle varsayılan değil), iş parçacığını durdurduktan sonra pthread_join()'u aramanız gerekir.Eğer iplik koparsa, ona katılmanıza gerek yoktur, fakat ne zaman sona erdiğini tam olarak bilemezsiniz (veya çıkışını belirtmek için başka bir yol eklemediğiniz sürece).

+0

Bu muteks çözümünü çoklu pthread için kullanmak için her iş parçacığına bir muteks ihtiyacım var, değil mi? Bu durumda bu çözümü tavsiye eder misiniz? –

+2

@RicardoCrudo Hayır, sadece bir muteks ... Eğer needQuit() 'başarılı bir şekilde kilitlerse, hemen kilidini açar ... sadece" main() "uzun bir süre boyunca muteksini tutar. Herhangi bir iş parçacığının, herhangi bir şey kilitlenmemişse, çıkıp çıkmayacağını kontrol etmek için 'needQuit()' yi kullanırlar ve sadece çok (çok kısa) bir an için kilitlerler. Sadece bir 'needQuit()' araması bir seferde başarılı olacaktır, ancak her bir iş parçacığı hala birbiri ardına başarılı bir çağrı alacaktır. – Dmitri

5

Birkaç küçük düşünceler:

  1. Sen iplik iptal etmek çalışıyorsunuz ancak yerinde iptal koşulları ertelenmiş iptali için ise hiçbir zaman herhangi çağırır, çünkü senin thread_do(), iptal asla iptal noktalarıdır işlevleri:

    Sen basit bir örnek kodda iplik katılmadan değiliz
    A thread's cancellation type, determined by 
    pthread_setcanceltype(3), may be either asynchronous or 
    deferred (the default for new threads). Asynchronous 
    cancelability means that the thread can be canceled at any 
    time (usually immediately, but the system does not guarantee 
    this). Deferred cancelability means that cancellation will 
    be delayed until the thread next calls a function that is a 
    cancellation point. A list of functions that are or may be 
    cancellation points is provided in pthreads(7). 
    
  2. ; Programınız bitmeden pthread_join(3) çağırır: @sarnold sizin iplik iptal noktalarıdır herhangi fonksiyonları uğramadan pthread_cancel() ile iptal edilemez varsayılan olarak belirttiği gibi

    After a canceled thread has terminated, a join with that 
    thread using pthread_join(3) obtains PTHREAD_CANCELED as the 
    thread's exit status. (Joining with a thread is the only way 
    to know that cancellation has completed.) 
    
İlgili konular