pthread_cleanup_push()/pthread_cleanup_Pop()の詳細


ちょうどスレッドの条件の変数を练习する时この2つの関数に出会って、この2つの関数の本の上で言うのは比较的にあいまいで、だからネット上で1篇の私の感じの言うとても良い1篇の文章を探し当てて、スレッドの终わりについて、大体以下のようです:一般的に、Posixのスレッドの终わりは2つの情况があります:正常な终わりと非正常な终わり.スレッドアクティブ呼び出しpthread_exit()またはスレッド関数からreturnは、スレッドを正常に終了させます.これは、予測可能な終了方法です.非正常な終了は、スレッドが他のスレッドの介入の下で、または不正なアドレスへのアクセスなどの自身の実行エラーによって終了することであり、このような終了方式は予見できない.
予測可能なスレッド終了でも異常終了でも、リソース解放の問題があり、実行エラーによる終了を考慮せずにスレッド終了時に自分の占有するリソース、特にロックリソースを順調に解放できることをどのように保証するかは、解決しなければならない問題である.
最も頻繁に発生する状況は、リソース排他ロックの使用です.スレッドは、臨界リソースにアクセスするためにロックされていますが、アクセス中に外部によってキャンセルされ、スレッドが応答キャンセル状態にあり、非同期で応答している場合、または排他ロックを開く前の運転経路にキャンセルポイントがある場合、臨界リソースは常にロック状態で解放されません.外部キャンセル操作は予見できないため、リソース解放のためのプログラミングを簡略化するメカニズムが必要である.
POSIXスレッドAPIにはpthread_が用意されているcleanup_push()/pthread_cleanup_pop()関数ペアは、リソースを自動的に解放するために使用されます.pthread_からcleanup_push()の呼び出しポイントからpthread_cleanup_pop()間のプログラムセグメントでの終了動作(pthread_exit()の呼び出しとキャンセルポイントの終了を含む)は、pthread_を実行します.cleanup_push()で指定したクリーンアップ関数.APIは以下のように定義される.
void pthread_cleanup_push(void (*routine) (void  *),  void *arg)
void pthread_cleanup_pop(int execute)

pthread_cleanup_push()/pthread_cleanup_pop()は先入後出のスタック構造管理を採用し、void routine(void*arg)関数はpthread_を呼び出すcleanup_push()時にクリーンアップ関数スタックに圧入し、pthread_を複数回cleanup_push()の呼び出しは、関数スタックをクリーンアップし、その関数チェーンを実行するときにスタックの反対の順序でポップアップする関数チェーンを形成します.executeパラメータはpthread_に実行されたことを示します.cleanup_pop()時にクリーンアップ関数をポップアップしながら実行するかどうかは、0は実行しないことを示し、0は実行ではない.このパラメータは、異常終了時のクリーンアップ関数の実行に影響しません.
pthread_cleanup_push()/pthread_cleanup_pop()はマクロ方式で実現され、これはpthreadである.hのマクロ定義:
#define pthread_cleanup_push(routine,arg)                                     
{ struct _pthread_cleanup_buffer _buffer;
_pthread_cleanup_push (&_buffer, (routine), (arg));
#define pthread_cleanup_pop(execute)
_pthread_cleanup_pop (&_buffer, (execute)); }
,pthread_cleanup_push() "{", pthread_cleanup_pop() "}", , 。 , "do some work" , pthread_mutex_unlock(mut), 。
work" , pthread_mutex_unlock(mut), 。
pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);
pthread_mutex_lock(&mut);
/* do some work */
pthread_mutex_unlock(&mut);
pthread_cleanup_pop(0);
, PTHREAD_CANCEL_ASYNCHRONOUS , , CANCEL
pthread_cleanup_push() pthread_mutex_lock() , pthread_mutex_unlock() pthread_cleanup_pop() , unlock
mutex , 。 , , PTHREAD_CANCEL_DEFERRED 。 ,POSIX
Linux pthread_cleanup_push_defer_np()/pthread_cleanup_pop_defer_np() ,

{ int oldtype;
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
pthread_cleanup_push(routine, arg);
...
pthread_cleanup_pop(execute);
pthread_setcanceltype(oldtype, NULL);
}
                      ,      :
pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);
pthread_mutex_lock(&mut);
/* do some work */
pthread_mutex_unlock(&mut);
pthread_cleanup_pop(0);
do some work pthread_mutex_unlock(&mut); ,
, do some work , , pthread_cleanup_push , , !

補足:スレッドホスト関数でreturnをアクティブに呼び出し、return文がpthread_に含まれている場合cleanup_push()/pthread_cleanup_pop()ペアでは、クリーンアップ関数の実行は起こらず、逆にsegment faultになります.