2016-10-27 6 views
0

以下のコードで、私の友人は、Linuxのコンテキスト切り替えとmutexロックでデッドロック状況を刺激しました。コンテキストスイッチは毎回動作しますか、予期しない動作が発生しますか?

#include <stdio.h> 
#include <pthread.h> 
pthread_mutex_t l1, l2; 
void* func1(); 
void* func2(); 

int main() 
{ 
    pthread_mutex_init(&l1, NULL); 
    pthread_mutex_init(&l2, NULL); 
    pthread_t t1, t2; 
    pthread_create(&t1, NULL, func1, NULL); 
    pthread_create(&t2, NULL, func2, NULL); 
    pthread_join(t1, NULL); 
    pthread_join(t2, NULL); 
} 

void* func1() 
{ 
    pthread_mutex_lock(&l1); 
    printf("\nl1 locked in func 1"); // 1 
    sleep(1); 
    printf("\ntrying to Lock l2 in func 1"); // 2 
    pthread_mutex_lock(&l2); 
} 

void* func2() 
{ 
    pthread_mutex_lock(&l2); 
    printf("\nl2 locked in func 2"); // 3 
    sleep(1); 
    printf("\ntrying to Lock l1 in func 2"); // 4 
    pthread_mutex_lock(&l1); 
} 

問題は、実行後、それは声明1,3印刷され、4 しかし、正しい出力は、文1,3と2

されている必要があります。しかし、私はにfunc2の中で睡眠の値を変更するとき睡眠(4)それは正常に動作します。

私は文2と4を書かないと、文1が印刷された後に文1と文3が出力されます。

その後func2の睡眠を変更した後、(1)(4)スリープ状態に、スリープ状態に戻ってそれを切り替える(1)正しい動作状態となり...

は、この予期しない動作のすべてのですか理由がありますこれが起こっている... またはこれらのすべての動作を修正する簡単な解決策は私が理解するのに役立ちます。おかげさまで

+3

私があなたのコードから見ることのできる唯一のことは、1が2の前に来て3が4の前に来ることです。それ以外は保証されません。 – Art

+3

行の最後に '\ n'を移動する必要があります。そうしないと、stdoutバッファはフラッシュされず、デッドロック前の最後のメッセージは表示されません。 – mch

+0

@mchはstdoutバッファを明示的にフラッシュする方法です – sharan

答えて

2

スレッドを生成しているときに、スレッドが生成した順に実行を開始する保証はありません。ときどきそれが起こりますが、それ以外の時はありません。 1が3よりも前に来るという保証はありません。とpthread_joinへの呼び出し後、いつでもfunc1が自分のスレッドで呼び出されることが保証されている唯一のことは、そのスレッドで返されるfunc1まで戻りません。 func2も同じです。スレッドの1つが他のスレッドの前に実行されることは、間違いなく保証されています。

sleepは、十分な同期メカニズムではありません。 sleepは、処理待ちがであり、少なくとも X秒であると定義されています。オペレーティングシステムがプロセスを10倍以上待つことは完全に合法です。おそらく、起こる可能性があります。特に、忙しいシステムで。ミックスsleepとスレッドと何かが起こる可能性があります。スレッドはお互いに非常に近い時間に実行され、システムのタイマーは無限の精度を持たない可能性が高い(ただし絶対に保証されていない)ので、sleepが "same時間 "("同じ時間 "は非常に危険な用語ですが、この場合、何らかのタイマー割込みと同じティックを意味します)。だからスレッドは一緒に目覚めさせられ、もう一方が目の前で起こされる保証はありません。それに関係なく、どちらが目の前で起こされても、どちらが最初に走り始めるのかはまだ分かりません。他のスレッドの前に実行されていたスレッドのいずれかを持っていた運があれば、確実にここで実行されます。

最終的にではなく、printfsの先頭に改行を入れることで、stdoutを適切にフラッシュしているわけではありません(どこから来たのでしょうか?理由は何もありません)。 printfsの最後に改行を追加し、stdoutが行バッファリングされている可能性が高いので、printfsは行末でフラッシュします。

また、最後にデッドロックを引き起こす以外の明らかな機能を持たないミューテックスがたくさんあります。 (考えにくいが)実際には、コードが書かれている方法は、それがスレッドで実行されているfunc2開始、ロックl2、再びプリントやスリープや版画、ロックl1とリターンがどのスレッドが実行を開始する前にいることは完全に可能

をですfunc1。これにより、l1をロックしようとするとハングアップするため、何も印刷されないfunc1につながります。

+0

代わりに、同期をsleepとして使用する代わりに、booleen変数を使用していますか?...または同期スレッドの最適な方法は何ですか? – sharan

+0

@sharan pthreadには、さまざまな方法で同期させる方法があります。 mutexes、rwlocks、障壁、条件変数、セマフォーなどがあります。複雑なトピックであるため、それらを読んでください。基本的なスレッドのチュートリアルでは、ロックについて説明します。ブール値はあなたをあまり良くしません。 – Art

関連する問題