質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Q&A

解決済

2回答

2489閲覧

定期処理と保存のタイミングが重なるとデッドロックしてしまう

nekonekoeditor

総合スコア13

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

0グッド

0クリップ

投稿2019/03/14 02:39

編集2019/03/14 15:32

前提・実現したいこと

UWPのテキストエディターを作っています
このテキストエディタでは定期的にシンタックスハイライトと自動保存の処理を実行していますが、そのタイミングにユーザーによる保存が行われると時々落ちたり、デッドロックしてしまいます
そこで自動保存の時だけ無理やりタイマーを止めるようにしましたが、あまりいい感じがしません
タイマーを止めずにこの現象を解決する方法を教えてほしいです

発生している問題・エラーメッセージ

原因を調べてみると自動保存のタイミングでlockrecursionexceptionが投げられていることが分かりました

該当のソースコード

C#

1 /// <summary> 2 /// それ自体で使用できる空白ページまたはフレーム内に移動できる空白ページ。 3 /// </summary> 4 public sealed partial class MainPage : Page 5 { 6 DispatcherTimer timer = new DispatcherTimer(); 7 ReaderWriterLockSlim rwlock = new ReaderWriterLockSlim(); 8 public MainPage() 9 { 10 this.InitializeComponent(); 11 this.timer.Tick += Timer_Tick; 12 this.timer.Interval = new TimeSpan(0,0,1); 13 this.timer.Start(); 14 } 15 16 private async void Timer_Tick(object sender, object e) 17 { 18 this.timer.Stop(); 19 await this.SaveAsync(); 20 this.timer.Start(); 21 } 22 23 private async Task SaveAsync() 24 { 25 this.StatusText.Text = "start"; 26 rwlock.EnterReadLock(); 27 await Task.Delay(100); //HeavyWork 28 rwlock.ExitReadLock(); 29 this.StatusText.Text = "end"; 30 } 31 32 private async void Button_Click(object sender, RoutedEventArgs e) 33 { 34 await this.SaveAsync(); 35 this.StatusText.Text = "saved!!!"; 36 } 37 }

試したこと

SemaphorSlimだとデッドロック発生する

補足情報(FW/ツールのバージョンなど)

{
"dependencies": {
"HockeySDK.UWP": "4.1.6",
"Microsoft.NETCore.UniversalWindowsPlatform": "5.3.3",
"Microsoft.Toolkit.Uwp.Notifications": "1.4.1",
"Prism.Unity": "6.3.0",
"Prism.Windows": "6.3.0",
"System.Text.Encoding.CodePages": "4.3.0",
"WinRTXamlToolkit.UWP": "2.3.0"
},
"frameworks": {
"uap10.0.15063": {}
},
"runtimes": {
"win10-arm": {},
"win10-arm-aot": {},
"win10-x86": {},
"win10-x86-aot": {},
"win10-x64": {},
"win10-x64-aot": {}
}
}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hihijiji

2019/03/14 04:06

省略せずに、現象が再現できる最小コードを掲載してください。
guest

回答2

0

ベストアンサー

System.Threading.Channelsを使う
をやってみるとか。

投稿2019/03/14 03:51

kiichi54321

総合スコア1984

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nekonekoeditor

2019/03/14 06:49

そういう方法があるんですね。普段は同期でバッファーから読み書きし、保存時だけ非同期でファイルに読み書きすることができるかは分かりませんが、調べてみます
guest

0

lockrecursionexceptionが出るということは、EnterReadLockが再帰的に何度も呼び出されているからです。

SaveAsyncはメインスレッドで動いていたようなので、Timer_TickでSaveAsyncが呼び出されている間にButton_Clickが呼び出されるとSaveAsyncがさらに呼び出されるため、複数回のEnterReadLockの呼び出しで、再帰的という認識になるのだと思われます。

コンストラクタで例外が出ないLockRecursionPolicyをするか、例外が出たら同時に書き込みしていると判断し、書き込みをしないような実装にするという方針になるかと思います。

投稿2019/03/15 01:43

ta.fu

総合スコア1664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nekonekoeditor

2019/03/15 03:28

メインスレッドでロックをかけようとしてるからそうなるんですね。そのやり方だとコストが高そうなのが気がかりですが、例外を捉える方向で行ってみます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問