Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9749

再入門C#:デッドロック

$
0
0

コンカレントプログラミングの本を読んでいると、必ずデッドロックの話がでてくるので、実際にデッドロックするのか試したくなった。

デッドロックするコード

DeadLock() メソッドをシングルスレッドしか許されていない箇所から呼び出すとデッドロックが起こる。例えばWPFのUIスレッドから、これを呼び出すとデッドロックが起こる。理由は task.Wait() を呼び出すとこのスレッドのところで、待ちが発生する。一方、WaitAsAsync() メソッドの方では、await で、Task.Delay() を呼んでいる。await のセクションに入るときに現在のスレッドのコンテキストを保存する。await の箇所が終わると、そのコンテキストをリストアするのだが、その時にそのコンテキストは、task.Wait() によってロックがかかっているために、デッドロックになる。

privateasyncTaskWaitAsAsync(){awaitTask.Delay(TimeSpan.FromSeconds(1));}privatevoidDeadLock(){Tasktask=WaitAsAsync();task.Wait();}

WPF アプリ

WPFは触ったことないけど、師匠のブログを読んで簡単なアプリを作ってみた。ボタンをおしていくと5回目で、Thread.Sleep() がかかり、10回目でこのデッドロックのロジックが呼ばれる。

MainWindow.xaml.cs
publicpartialclassMainWindow:Window{publicMainWindow(){InitializeComponent();this.DataContext=newPrefecture();}privateasyncTaskWaitAsAsync(){awaitTask.Delay(TimeSpan.FromSeconds(1));}privatevoidDeadLock(){Tasktask=WaitAsAsync();task.Wait();}privateintcount=0;privatevoidButton_Click(objectsender,RoutedEventArgse){varbutton=(Button)sender;button.Content=string.Format($"{++count} times.");if(count==4){button.Content=string.Format($"Sleep 10 sec....");}if(count==4){Thread.Sleep(TimeSpan.FromSeconds(10));}if(count==10){button.Content=string.Format($"DeadLock....");}if(count==11){DeadLock();}}}
MainWindow.xaml
<Window x:Class="WPFSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPFSample"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition>
            </RowDefinition>
            <RowDefinition>
            </RowDefinition>
        </Grid.RowDefinitions>

    <ComboBox ItemsSource="{Binding Path=Data}" x:Name="comboBox" Grid.Row ="0" Grid.Column="0"/>
    <Button Content="0回" Grid.Row="1" Grid.Column="0" Click="Button_Click"/>
    </Grid>
</Window>

デッドロックに行く直前なら、プルダウンなどの操作できるが、一旦行ってしまうと何もできなくなる。

image.png

操作不能

image.png

回避方法

ConfigureAwait() を使うと、コンテキストのリストアをするか否かを制御できる。falseにすると、コンテキストをリストアして元のスレッドに戻ろうとしない(違うスレッドを使う)ので、デッドロックが起こらなくなる。

privateasyncTaskWaitAsAsync(){awaitTask.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);}

Viewing all articles
Browse latest Browse all 9749

Trending Articles