pthread_cancelを試す。

はじめに

 メインスレッドから生成したスレッドを途中で終了させるにはどうするのかを調査中、pthread_killが使えることがわかったが、
【POS44-C. シグナルを使用してスレッドを終了しない】
では、pthread_cancelを使用せよとあった。使ったことがないので、サンプルを作りながら、挙動を確認してみた。
それをまとめた記事である。

今回のサンプルソースこちら

pthread_cancelの挙動まとめ

 pthread_cancelの挙動は、大きく分けて4つある。

  • キャンセルを許可/不許可 ・・・A
  • 遅延取り消し/即時取り消し(非協調的) ・・・B

A×B(=2×2)の4つである。

【A】は、キャンセルされる側のスレッド上で、pthread_setcancelstate()で設定可能。
【B】は、キャンセルされる側のスレッド上で、pthread_setcanceltype()で設定可能。

キャンセル許可 キャンセル不許可
遅延取り消し
即時取り消し

デフォルトの動作

 上記表の【1】にあたる。

サンプル

 デフォルトの動作がわかるサンプルを下記に示す。

andre@andre-VirtualBox:~/work/c/pthread_cancel$ cat main.c
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>

#define FIB_N   40

unsigned long
fib( int n )                   ★フィボナッチ数を計算
{
    if( n < 0 )     return 0;
    if( n == 0 )    return 1;
    if( n == 1 )    return 1;
    if( n > 1 )     return fib( n-1 ) + fib( n-2 );
}

int
thread( void* arg )            ★ cancelされる側のスレッド
{
    int i = 0;
    unsigned long    ret = 0;

    printf( "sub thread fib calc start...\n" );
    for( i = 0; i < FIB_N; i++ )
    {
//        printf( "for:%d\n", i );
        ret = fib( i );
//        printf( "fib(%d)=%lu\n", i, ret );
    }
    printf( "sub thread fib calc finish!\n" );   ★ 遅延取り消しのキャンセルポイント
    printf( "finish thread!\n" );                ★ このメッセージは出力「されない」

    return 0;
}

int
main( void )                  ★ cancelする側のスレッド
{
    int         ret = 0;
    pthread_t   th;

    ret = pthread_create(   &th,
                            NULL,
                            ( void* )thread,
                            NULL );

    printf( "main thread sleep...\n" );
    sleep( 1 );
    printf( "main thread wake up!\n" );

    printf( "do thread cancel.\n" );
    pthread_cancel( th );     ★スレッドをキャンセルする

    pthread_join( th, NULL ); ★ joinしないとメモリリークする。

    return 0;
}

実行結果

andre@andre-VirtualBox:~/work/c/pthread_cancel$ ./test_pthread_cancel 
main thread sleep...
sub thread fib calc start...
main thread wake up!
do thread cancel.            ★ キャンセル実行
sub thread fib calc finish!  ★ キャンセルポイント

【sub thread fib calc finish!】のメッセージで、フィボナッチ数をすべて計算してから、スレッドが終了しているのがわかる。