2017-09-21 11 views
1

Iは約APUE 3rd、11.6.1ミューテックスを読み、そこにロック約例であり、この章でミューテックスのロックを解除する:pthread_mutex_destroyを使ってLinuxでmutexを安全かつ正しく破壊するには?

foo_releで
struct foo { 
    int    f_count; 
    pthread_mutex_t f_lock; 
    int    f_id; 
    /* ... more stuff here ... */ 
}; 

struct foo * 
foo_alloc(int id) /* allocate the object */ 
{ 
    struct foo *fp; 

    if ((fp = malloc(sizeof(struct foo))) != NULL) { 
     fp->f_count = 1; 
     fp->f_id = id; 
     if (pthread_mutex_init(&fp->f_lock, NULL) != 0) { 
      free(fp); 
      return(NULL); 
     } 
     /* ... continue initialization ... */ 
    } 
    return(fp); 
} 

void 
foo_hold(struct foo *fp) /* add a reference to the object */ 
{ 
    pthread_mutex_lock(&fp->f_lock); 
    fp->f_count++; 
    pthread_mutex_unlock(&fp->f_lock); 
} 

void 
foo_rele(struct foo *fp) /* release a reference to the object */ 
{ 
    pthread_mutex_lock(&fp->f_lock); 
    if (--fp->f_count == 0) { /* last reference */ 
     pthread_mutex_unlock(&fp->f_lock); 
     pthread_mutex_destroy(&fp->f_lock); 
     free(fp); 
    } else { 
     pthread_mutex_unlock(&fp->f_lock); 
    } 
} 

、そこpthread_mutex_unlockのとpthread_mutex_destroyの間の競合状態があるので、Bスレッドは、のスレッドpthread_mutex_unlockとpthread_mutex_destroyの間でpthread_mutex_lockを呼び出すことができます。スレッドは未定義の動作を引き起こします(ロックされたミューテックスを破棄しようとすると、未定義の動作になります)。私は正しい?もし私が正しいのであれば、pthread_mutex_destroyを使って、それを正しく動作させる方法、またはLinuxでmutexを安全かつ正しく破壊する方法は?

答えて

1

pthread_mutex_destroy()のためのPOSIX仕様は言う:

ロックが解除され、初期化されたmutexを破棄しても安全でなければなりません。スレッドBがfoo_rele()if文のelse句でpthread_mutex_unlock()を呼び出す場合、スレッドBのpthread_mutex_unlock()呼び出しがミューテックスをアンロックした後に、それが唯一存在し得ている可能性があるため、スレッドAがpthread_mutex_destroy()を呼び出すようにするために、それが安全だということを意味

これは、スレッドAがミューテックスのロックを解除した後に、他のスレッドがカウントを0 - > 1から増やすことができないように、参照カウントが正しいことを前提としています。言い換えれば、refcountが0に下がったところで、おそらくfoo_hold()を呼び出すかもしれない別のスレッドは存在しません。

APUEは、右のコード例の後の説明でこれを言及:この例では

は、我々はFiのND foo_holdを呼び出す前にオブジェクトをスレッドどのように無視してきました。参照カウントがゼロであっても、foo_holdの呼び出しで別のスレッドがmutexでブロックされている場合は、foo_releがオブジェクトのメモリを解放するのは間違いです。オブジェクトをメモリから解放する前にオブジェクトが見つからないようにすることで、この問題を回避できます。以下の例でこれを行う方法を見ていきます。

+0

あなたは、サンプルコードをチェックするために** ** 11.6.2デッドロック回避を参照してくださいでした、私は右だ、スレッドが唯一の直接ではない 'foo_hold'、' foo_find'を呼び出すことにより、オブジェクト参照を増やすことができると思います? – cong

+1

はい、 'foo_find()'だけが 'foo_hold()'を呼び出します。 'foo_rele()'は、refcountを0に減らそうとすると、mutexを保持している間にハッシュテーブルからその項目を削除するので、他のスレッドは 'foo'オブジェクトへのポインタを再び取得できません。そのようなことが起こると、mutexはロック解除され、 'foo'オブジェクトのmutexは破壊され、' foo'オブジェクト自体は解放されます。 –

+0

** foo_findのfoo_hold(fp);コードは、バージョン1のデュアルロック回避**の章のサンプルコードの2つのバージョンが、 'pthread_mutex_lock(&fp-> f_lock) ; fp-> f_count ++; pthread_mutex_unlock(&fp-> f_lock); ' と関数' foo_hold'を削除してください。 バージョン2では、 'foo_hold'関数を単に削除する必要があります。一方、それは役に立たず、危険ですが、ユーザーはインタフェースを誤用する可能性があります。 – cong

関連する問題