デッドロックを引き起こす最短コード


11

デッドロックを作成する最短のコードを記述します。コードの実行を停止する必要があるため、これは機能しません。

public class DeadlockFail extends Thread{ //Java code
    public static void main(String[]a){
        Thread t = new DeadlockFail();
        t.start();
        t.join();
    }
    //this part is an infinite loop; continues running the loop. 
    public void run(){while(true){}}
}

ほぼ確実にコードがデッドロックになることを確認する必要はありません(無限に実行するとデッドロックになります)。


同じ(再入不可)ロックを同じスレッドから2回ロックしようとすると、デッドロックとしてカウントされますか?(申し訳ありませんが、サンドボックスでこの質問に気づきませんでした)
John Dvorak '28

@JanDvorakあるスレッドが取得できない何かを待っているためにコードの実行が停止する状況が発生しますか(別のスレッドがそれを保持していて、最初のスレッドの内容を待っているため)?それとも1つのスレッドですか?1つのスレッドでこのような状況を作成できる場合は、問題ありません。デッドロックに関するwikepediaの記事を読んでください。それが私が期待していることです。
ジャスティン

2
Code execution must haltわかりません。停止した場合、それはどのようにデッドロックになりますか?ろくでなしのようにスピンロックするだけでなく、何かを待っているということですか?
Cruncher 2013年

@Cruncher動作しない例を見てください。ループが実行され続けるため、コードの実行は停止しません。はい私は回転するのではなく待つことを意味します。
ジャスティン

Dyalog APLでUIスレッドを待機させることができるとしたら、それはJavaScriptの回答を得られる可能性があるということですか?私はその種の考え方がこの答えへの扉を開くだろうと思っていますが、Javascript 6 "wait()" ... ermmm。番号。関連:スレッドがデッドロックする可能性はありますか?
Nathan Cooper、

回答:


11

ダイアログAPL(10)

⎕TSYNC⎕TID

⎕TSYNC指定されたスレッドが終了するまでスレッドを待機させ、 ⎕TID現在のスレッドを提供します。

ただし、Dyalog APLはデッドロックを認識できるため、すぐに次のように応答します。

DEADLOCK

おもしろいのは、余分なスレッドを生成する必要すらなく、UIスレッドがそれ自体を待機させることで十分です。

これが不正行為であり、実際に新しいスレッドが必要な場合は、27文字で実行できます。

{∇⎕TSYNC&{⎕TSYNC⎕TID+1}&0}0

F & xFvalueの新しいスレッドで実行されx、スレッドIDを返します。そう:

  • {⎕TSYNC⎕TID+1}&0 IDが1より大きいスレッドと同期するスレッドを作成します。
  • ⎕TSYNC& 前のスレッドと同期する新しいスレッドを作成し、作成されたスレッドより1つ大きいIDを取得します(他に何もスレッドを作成していないと仮定)。
  • 無限ループが発生します(デッドロックが発生するまでスレッドを作成し続けます)。

これは、最初のスレッドが実行を開始する前に2番目のスレッドが作成されるとすぐにデッドロックします。

9:DEADLOCK

2バイト節約:⎕TSYNC 0'. ⎕TID`は0です。
アダム

8

行く、42

package main
func main(){<-make(chan int)}

それがどのように機能するかを提供しなかったことに対する謝罪、投票者 これにより、intの匿名チャネルが作成され、そこから読み取られます。これにより、値がチャネルに送信されるまでメインスレッドが一時停止します。他のスレッドがアクティブではないためデッドロックが発生することはありません。


2
それはどのように機能しますか?
ジャスティン

4

ルビー、39文字

T=Thread;t=T.current;T.new{t.join}.join

Johannes KuhnのJavaの回答から恥知らずに盗まれたクロス結合を使用するという考え。

コードを特定の環境に合わせて調整すると、4文字(35まで)を削ることができます。JRubyのコンソールIRBはシングルスレッドです。

T=Thread;T.new{T.list[0].join}.join


これは私の以前の解決策です:

mutexでスレッドがスタックするのは簡単です。

m=Mutex.new;2.times{Thread.new{m.lock}}

しかし、これは適切なデッドロックではありません。2番目のスレッドが技術的に最初のスレッドを待機していないためです。Wikipediaによると、「ホールドアンドウェイト」はデッドロックの必須条件です。最初のスレッドは待機せず、2番目のスレッドは何も保持しません。

ルビー、 97 95文字

m,n=Mutex.new,Mutex.new
2.times{o,p=(m,n=n,m)
Thread.new{loop{o.synchronize{p.synchronize{}}}}}

これは古典的なデッドロックです。2つのスレッドが2つのリソースを求めて競合し、成功した場合は再試行します。通常、私のマシンでは1秒以内にスタックします。

しかし、無限に多くのスレッド(どれもが無限にCPUを消費し、その一部がデッドロックになる)が問題ない場合は、

ルビー、 87 85文字

m,n=Mutex.new,Mutex.new
loop{o,p=(m,n=n,m)
Thread.new{o.synchronize{p.synchronize{}}}}

私のテストによると、スレッドカウントが約4700に達した後に失敗します。うまくいけば、各スレッドが実行される機会があるまで失敗しません(したがって、デッドロックまたは新しいロックのためのスペースを終了して解放します)。私のテストによると、障害が発生した後、スレッド数は減少しません。つまり、テスト中にデッドロックが発生しました。また、IRBはテスト後に死亡しました。


なぜ余分なop変数が必要なのですか?あなただけ渡すことはできませんmし、n新しいスレッドのために?
Johannes Kuhn

@JohannesKuhn mおよびnグローバルです。両方のスレッドは同じ順序でそれらを参照します。oおよびpスレッドローカル(ループ反復にスコープ)です。使用t[...]することはおそらく高価になるでしょう、そして私はクロージャー経由でスレッドにパラメーターを渡すより良い方法を見ることができません。余分なパラメーターを追加newすると、コードが2文字長くなります。
John Dvorak

@JohannesKuhn私はあなたが私があなたの論理のいくつかを借りたことを気にしないことを願っています
John Dvorak

私は気にしません。よくやった。
Johannes Kuhn

メインスレッドにいると仮定すると、これを使用して32文字までT=Thread;T.new{T.main.join}.join
シェーブ


4

Bash + GNU coreutils、11バイト

mkfifo x;<x

x現在のディレクトリに浮遊FIFO を作成します(そのため、その名前のファイルは必要ありません)。FIFOは通常のファイルと同じ方法で削除できるため、消去するのは難しくありません。

FIFOには書き込み側と読み取り側があります。別のプロセスが別のプロセスを開くまで、あるブロックを開こうとすると、これは意図的に同期プリミティブとして設計されたようです。ここにはスレッドが1つしかないため、でスレッドを開こうとすると、すぐ<xに行き詰まります。(別のプロセスから問題のFIFOに書き込むことで、デッドロックを解除できます。)

これは、2つのリソースがあり、2つのスレッドにそれぞれ1つあり、もう1つが必要な場合のデッドロックとは異なる種類のデッドロックです。むしろ、この場合、リソースはゼロであり、プロセスはそれを必要とします。他の回答に基づいて、これは重要だと思いますが、デッドロック純粋主義者がその回答をどのように拒否したいのか理解できます。

考えてみると、実際には3つのデッドロックのような状況が考えられます。

  1. 「従来の」デッドロック:2つのスレッドはそれぞれ、他のスレッドによって保持されているロックが解放されるのを待っています。

  2. 単一のスレッドがロックが解放されるのを待っていますが、それ自体がロックを保持しています(したがって、それ自体がロックを解放できないようにブロックしています)。

  3. 単一のスレッドが同期プリミティブが解放されるのを待っていますが、同期プリミティブは自然にロックされた状態で開始され、外部でロックを解除する必要があります。そのためのプログラムは何もプログラムされていません。

これはタイプ3のデッドロックであり、他の2つとは根本的に異なります。理論的には、問題の同期プリミティブのロックを解除するプログラムを記述して実行できます。言った、同じことが多くの言語はあなたがいない(あなたが所有していないロックを解除できるようにすることを考えると、1型および2型のデッドロックにも適用されるはずに、あなたがする理由があった場合にはそうする理由がないだろうそもそもロックを使用しますが、機能します…)。また、次のようなプログラムを検討する価値があります。mkfifo x;<x;echo test>x; そのプログラムは、タイプ2のデッドロックの反対のようなものです(FIFOの両端を開こうとしますが、もう一方の端を開くまで、一方の端を開くことはできません)。この後は決して実行されないコード!問題は、ロックがデッドロックされているかどうかがロックの使用の背後にある意図に依存しているため、客観的に定義することが難しいことです(特に、このようなロックの唯一の目的が故意にデッドロックを生成することである場合)。 )。



2

glibcを使用したbash、6バイト

古いスレッドを復活させて申し訳ありませんが、抵抗することができませんでした。

ルートとして:

pldd 1

man plddから:

バグ
glibc 2.19以降、plddは壊れています:実行するとハングします。それが修正されるかどうかは不明です。


オリジナルが時間に敏感でない限り、古いトレッドで答えることは問題ありません。
アドホックガーフハンター2016

2

Java、191

class B extends Thread{public static void main(String[]a)throws Exception{new B().join();}Thread d;B(){d=Thread.currentThread();start();}public void run(){try{d.join();}catch(Exception e){}}}

非ゴルフ:

class B extends Thread {
    Thread d;
    public static void main(String[] args) throws Exception {
        new B().join();
    }
    B() { // constructor
        d = Thread.currentThread();
        start();
    }
    public void run() {
        try {
            d.join();
        } catch (Exception e) {
        }
    }
}

新しいスレッドを開始し、そのjoin上で(このスレッドが完了するまで待機します)、新しいスレッドは元のスレッドと同じことを行います。


Error代わりに投げてキャッチすることで短くできますExceptionか?
mbomb007

いいえ。Thread.join()InteruptedExceptionサブクラスではないをスローしErrorます。
ヨハネ

2

Tcl、76

package r Thread;thread::send [thread::create] "thread::send [thread::id] a"

デッドロック。

これにより、新しいスレッドが作成され、他のスレッドに私のスレッドにメッセージ(実行するスクリプト)を送信するように指示します。

ただし、他のスレッドへのメッセージの送信は、通常、スクリプトが実行されるまでブロックされます。そして、それがブロックしている間、メッセージは処理されないので、両方のスレッドは、他のスレッドがメッセージを処理するのを待ちます。


これはどのように作動しますか?
John Dvorak

thread::send他のスレッドで実行されるスクリプトをキューに入れ、それが完了するのを待ちます。だから、最後に、私たちはスレッド2のため1つの待機スレッド、およびスレッド1の2待ちスレッドいる
ヨハネス・クーン

1

monitor-abuseを使用した代替Java(248文字)

class A{public static void main(String args[]) throws Exception{final String a="",b="";new Thread(new Runnable(){public void run(){try {synchronized(b){b.wait();}} catch (Exception e) {}a.notify();}}).start();synchronized(a){a.wait();}b.notify();}}

1

Scala、104バイト

class A{s=>lazy val x={val t=new Thread{override def run{s.synchronized{}}};t.start;t.join;1}};new A().x

レイジーval初期化ブロックは、条件が満たされるまで一時停止します。この条件は、lazy val xの値を読み取ることによってのみ満たすことができます。この条件を完了することになっている別のスレッドは、そうすることはできません。したがって、循環依存が形成され、遅延valを初期化できません。


これはどのように作動しますか?
Addison Crump、2015年

説明を追加しました。
Martin Seeler、2015年

1

Kotlin、35/37/55バイト

一般的なテーマ:Thread.currentThread().join()

現在の実行スレッドは、自分自身が死ぬのを待って無効になっているため、JVMのバグ/この提出に対する非常に特殊なコードを除外すると、これは決して戻りません。


邪悪なプロパティ:35バイト(非競合):35バイト

val a=Thread.currentThread().join()

プロパティ宣言が有効な場所にこれを置くと、初期化している人はだれでもデッドロックします。トップレベルのプロパティの場合、それはそのファイルのマップされたJVMクラスを初期化するクラスローダーになります(デフォルトでは[file name]Kt.class)。

「これをどこでもトップレベルのプロパティとして置く」ことは制限的であるため、競合しません。


機能:37バイト

fun a()=Thread.currentThread().join()


main():55バイト

fun main(a:Array<String>)=Thread.currentThread().join()


1

PowerShell、36 28 23バイト

gps|%{$_.waitforexit()}

自己デッドロック。すべてのプロセスを取得し、各プロセスがGet-Process終了するまで辛抱強く待機します...プロセスはそれ自体で待機しているため、ほとんど発生しません。

編集-RomanGräfのおかげで5バイト節約


(gps)|%{$_.waitforexit()}3バイト短く、すべてのプロセスが終了するのを待ちます。
RomanGräf2016年

@RomanGräf確かに、gpsその場合は括弧が不要なので、合計で5バイト節約されました。
AdmBorkBork 2016年

0

C(Linuxのみ)、31バイト- オンラインでお試しください!

main(a){syscall(240,&a,0,a,0);}

システムコール240(0xf0)はfutex(2)または高速ユーザー空間ミューテックスです。ドキュメントには、最初の引数はfutexへのポインタであり、2番目の引数は操作(0はFUTEX_WAIT、つまり別のスレッドがfutexのロックを解除するまで待機する)であることを示しています。3番目の引数は、ロックされている間にfutexが期待する値で、4番目の引数はタイムアウトへのポインターです(タイムアウトがない場合はNULL)。

明らかに、futexをアンロックするスレッドは他にないので、自分で指定したデッドロックで永久に待機します。topデッドロックスレッドから予想されるとおり、プロセスがCPU時間を使用していないことを(または他のタスクマネージャを介して)確認できます。



0

BotEngine、3x3 = 9(9バイト)

v
lCv
> <

ステップ5は、2つのボットが相互に移動するのを無期限に待機することで終了します... 1つのボットは右下の正方形から移動するのを待っているため移動できません。もう1つのボットは移動を待機しているため移動できません一番下の中央の正方形から移動する最初のボット。


0

ウォーターフォールモデル(レシオフォール)、13バイト

[[2,1],[1,1]]

オンラインでお試しください!

これは、面白そうな楽しい答えです。これは、ウォーターフォールモデルで可能な限り最も単純な無限ループです(ウォーターフォールモデルの変数は、他に何も起こらないときに繰り返しデクリメントします。このプログラムは、デクリメントするたびに自動的にインクリメントする変数を定義しているため、何も起こりません)。

質問は、無限ループではなく、デッドロックを要求します。ただし、特定の実装の動作を利用できます。最適化レベル2以上(デフォルトは3)で、インタプリタのRatiofallは無限ループを検出し、それを最適化してデッドロックにします!したがって、少なくとも言語がその実装によって定義されると考える場合(通常、このサイトではそうです)、このプログラムは、無限ループではなく、実際にデッドロックを定義します。

デッドロックの証拠は、Try it Online!のタイムレポートから確認できます。上記のリンク:

Real time: 60.004 s
User time: 0.006 s
Sys. time: 0.003 s
CPU share: 0.01 %
Exit code: 124

プログラムは60秒間(TIOが自動的に終了するまで)実行されましたが、そのほとんどの時間、CPU使用率、プログラムの実行時間、プログラムに代わってカーネルが費やす時間はありませんでした。

さらに強力な証拠を得るために、Ratiofallを次のようなシステムコールレベルのデバッガーで実行できますstrace。Linuxでfutexこれを行うと、解放されないロックを取得しようとするシステムコールでインタープリターがブロックされることが示されます。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.