2011-10-31 1 views
20

私はスレッドを作成し、それを無限ループに入れます。 valgrindでコードをチェックするとメモリリークが発生します。ここに私のコードはあります:ループの外から無限ループにあるpthreadをどのようにして削除できますか?

スレッドはメインで作成され、thread_do()は常に実行されます。 2時間後にメインの中からそれを殺す方法はありますか?私はpthread_detach(th)pthread_cancel(th)の両方を試しましたが、まだ漏れがあります。

+3

pthreadsをキャンセルすると、スレッドは割り当てられたメモリをクリーンアップする機会がないことを意味します。 –

+2

私はこれをグローバルな 'keepalive = 1'だけで解決しました。それから、while(1)をwhile(keepalive)に変更しました。スレッドを強制終了するには、変数キープアライブの値を0に変更してください。 – Pithikos

答えて

32

@sarnoldは、あなたのスレッドが取り消しポイントである任意の関数を呼び出すことなくpthread_cancel()をキャンセルすることはできませんデフォルトでは、指摘...しかし、このことができますようにpthread_setcanceltype()を使用して変更して、スレッドのキャンセルタイプを遅延の代わりに非同期に設定します。これを行うには、ループを開始する前に、スレッド関数の開始付近にpthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);のようなものを追加します。 pthread_cancel(th)main()から呼び出して、スレッドを終了することができます。

このようにスレッドをキャンセルすると(非同期であるかどうかに関係なく)、スレッド関数で割り当てられたリソースはクリーンアップされません(コメント内のKevinが指摘するように)。きれいにこれを行うためには、次のことができます。

  • スレッドが(バッファを割り当てるmalloc()を使用して例えば)それが終了する前にクリーンアップする必要が何もしないことを確認してください
  • をあなたには、いくつかの方法を持っていることを確認してくださいスレッドが終了した後のスレッドの後のクリーンアップ
  • pthread_cleanup_push()pthread_cleanup_pop()を使用して、スレッドが取り消されたときにクリーンアップハンドラを追加してリソースをクリーンアップします。リソースの割り当てとクリーンナップハンドラの追加の間にスレッドがキャンセルされる可能性があるため、キャンセルタイプが非同期の場合、これは依然として危険です。
  • pthread_cancel()を使用しないようにして、スレッドが終了するタイミング(長時間実行されるループでチェックされる)を判断する条件を確認してください。スレッドは終了自体をチェックするので、チェック後に必要なクリーンアップを実行できます。

    #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; 
    } 
    

    スレッドではない場合:最後のオプションを実装する1つの方法は、フラグとしてミューテックスを使用して、ループテストで使用する機能に包まれpthread_mutex_trylock()でそれをテストすることです

(通常はデフォルトではありません)、スレッドを停止した後にpthread_join()に電話する必要があります。スレッドがデタッチされている場合は、スレッドに参加する必要はありませんが、スレッドが終了するタイミングを正確に把握することはできません。

+0

複数のpthreadにこのmutexソリューションを使用するには、スレッドごとに1つのmutexが必要でしょうか?この場合、このソリューションをお勧めしますか? –

+2

@RicardoCrudoいいえ、ただ一つのミューテックス...もし 'needQuit()'がそれをうまくロックすれば直後にロックを解除します... 'main()'はミューテックスを長時間保持します。 'needQuit()'を使って終了するかどうかをチェックするスレッドは、mutexがロックされていなければ終了し、非常に短い時間だけロックします。一度に1つの 'needQuit()'コールが成功するだけですが、各スレッドは順番に呼び出しを成功させます。 – Dmitri

5

いくつかの小さな思考:

  1. あなたのスレッドをキャンセルしようとしているが、代わりにキャンセルポリシーが遅延取り消しのためであれば、それはいずれかを呼び出すことはありませんので、ごthread_do()は、キャンセルされることはありませんキャンセルポイントの関数:

    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. あなたの簡単なサンプルコードでスレッドに参加していません。あなたのプログラムの終了前pthread_join(3)を呼び出す:

    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.) 
    
関連する問題