C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[10]: エラー:ContextSwichDeadLock


(過去ログ 102 を表示中)

[トピック内 15 記事 (1 - 15 表示)]  << 0 >>

■60969 / inTopicNo.1)  エラー:ContextSwichDeadLock
  
□投稿者/ ER (1回)-(2011/07/27(Wed) 20:32:48)

分類:[VB.NET/VB2005 以降] 

VisualBasic2010を使用しています。
指定した日時になったら、実行するというプログラムを作成しています。

↓プログラム
Dim xDay As String '設定日時
Dim genZai As String '現在日時
Dim yyyy As String
yyyy = Form3.TextBox5.Text
Dim mm As String
mm = Form3.TextBox6.Text
Dim dd As String
dd = Form3.TextBox7.Text
Dim hh As String
hh = Form3.TextBox1.Text
Dim nn As String
nn = Form3.TextBox2.Text
Dim ss As String
ss = Form3.TextBox3.Text

'現在日時をセット
genZai = Format(Now, "yyyyMMddHHmmss")
'設定日時をセット
xDay = yyyy & mm & dd & hh & nn & ss

Dim Count As String

Count = 1
Do Until Count = 0


If genZai = xDay Then

Count = 0
Else
Count = 1
End If

Loop 'ループさせる

If Count = 0 Then
'ここに実行する物が入る

End If

実際に実行しようとすると、指定した日時を過ぎてから、『ContextSwichDeadLockが検出されました』というエラーが出ます。

↓このエラーの詳細
CLR は、COM コンテキスト 0x49b9d0 から COM コンテキスト 0x49bcb0 へ 60 秒で移行できませんでした。ターゲット コンテキストおよびアパートメントを所有するスレッドが、ポンプしない待機を行っているか、Windows のメッセージを表示しないで非常に長い実行操作を処理しているかのどちらかです。この状態は通常、パフォーマンスを低下させたり、アプリケーションが応答していない状態および増え続けるメモリ使用を導く可能性があります。この問題を回避するには、すべての Single Thread Apartment (STA) のスレッドが、CoWaitForMultipleHandles のようなポンプする待機プリミティブを使用するか、長い実行操作中に定期的にメッセージをポンプしなければなりません。

なにか解決法はありますか?
引用返信 編集キー/
■60970 / inTopicNo.2)  Re[1]: エラー:ContextSwichDeadLock
□投稿者/ 逆運の覇者 (40回)-(2011/07/27(Wed) 20:54:45)
単純なループで負荷を不必要にかけ続けているのでフリーズした状態になっています。
それはそういうエラーメッセージです。
ERさんのプログラムがCPUを待機して休む時間を与えずに動かしまくっているのです。
これを参考にすると良いかと。

時間がかかる処理での「応答なし」を回避するには?
ttp://www.atmarkit.co.jp/fdotnet/dotnettips/136doevents/doevents.html

引用返信 編集キー/
■60980 / inTopicNo.3)  Re[2]: エラー:ContextSwichDeadLock
□投稿者/ uni (4回)-(2011/07/28(Thu) 10:08:06)
指定日時に実行させたいのであれば実行部分を独立させてそれをタスクスケジューラで呼出すとかの方が
日時の制御を実装しなくてすむので楽じゃないですかね。

それがダメなら単純なループはやめてタイマーコントロールを使用した方がまだましに思えます。
引用返信 編集キー/
■60989 / inTopicNo.4)  Re[2]: エラー:ContextSwichDeadLock
□投稿者/ ER (2回)-(2011/07/28(Thu) 16:01:13)
No60970 (逆運の覇者 さん) に返信
> 単純なループで負荷を不必要にかけ続けているのでフリーズした状態になっています。
> それはそういうエラーメッセージです。
> ERさんのプログラムがCPUを待機して休む時間を与えずに動かしまくっているのです。
> これを参考にすると良いかと。
> 
> 時間がかかる処理での「応答なし」を回避するには?
> ttp://www.atmarkit.co.jp/fdotnet/dotnettips/136doevents/doevents.html
> 
エラーについては、解決いたしました。
ですが今度は、プログラムが正常に動作しないという事が起こりました。
どこかコードにおかしい所はありますか?
ヒント程度でいいので、お教え頂ければ光栄です。

引用返信 編集キー/
■60992 / inTopicNo.5)  Re[3]: エラー:ContextSwichDeadLock
□投稿者/ みきぬ (979回)-(2011/07/28(Thu) 16:17:46)
No60989 (ER さん) に返信
> ヒント程度でいいので、お教え頂ければ光栄です。

エスパー回答でよければ。

・設定日時をゼロサプレスしてなくて一致しない。

・監視間隔が長くて設定日時をまたいでしまっている。


引用返信 編集キー/
■60993 / inTopicNo.6)  Re[3]: エラー:ContextSwichDeadLock
□投稿者/ ユースケ (1回)-(2011/07/28(Thu) 16:25:32)
No60989 (ER さん) に返信
> エラーについては、解決いたしました。
> ですが今度は、プログラムが正常に動作しないという事が起こりました。
> どこかコードにおかしい所はありますか?

どのようにエラーを解決したのか、その結果、どのようにプログラムが正常に動作しないのか
これでは分かりませんよ。
引用返信 編集キー/
■60997 / inTopicNo.7)  Re[4]: エラー:ContextSwichDeadLock
□投稿者/ みきぬ (980回)-(2011/07/28(Thu) 16:55:23)
No60993 (ユースケ さん) に返信
> どのようにエラーを解決したのか、その結果、どのようにプログラムが正常に動作しないのか
> これでは分かりませんよ。

『実際に実行しようとすると、指定した日時を過ぎてから、…』

とあるから、もともと条件にヒットしてなかったんじゃないか、と予想。
引用返信 編集キー/
■61003 / inTopicNo.8)  Re[5]: エラー:ContextSwichDeadLock
□投稿者/ 逆運の覇者 (41回)-(2011/07/28(Thu) 18:26:31)
プログラムは思ったとおりに動くのではありません。書いたとおりに動くのです。
「思ったとおりに動かない=正常に動かない」ではありません。
この表現はあいまいで、例外エラーが出たとも取れるし、
例外エラーが出ないけれど思ったとおりに動いてくれないとも取れます。
この場合、後者であるという想像はつきますが、不確定であることは時間の無駄になりかねません。

さて、問題点についてですが
指定の時間になってもこのループを抜けることができないことが問題です。
これでは、指定の時間になっても実行できないのがわかりますね?
実行する処理がループの外にあるのにもかかわらず、いつまでもループの中にいるのですから。
対処としては、Count=0 の下に Break を加えてくださいな。
それでループを脱出します。



みきぬさんに返信
>『実際に実行しようとすると、指定した日時を過ぎてから、…』
指定した日時がたまたまエラーメッセージが出るタイミングに近かったのでしょう。
たまたまというか、テストしているときはさほど現在時刻から離れた時間を指定しませんから。
引用返信 編集キー/
■61005 / inTopicNo.9)  Re[6]: エラー:ContextSwichDeadLock
□投稿者/ ER (3回)-(2011/07/28(Thu) 20:09:35)
No61003 (逆運の覇者 さん) に返信
> さて、問題点についてですが
> 指定の時間になってもこのループを抜けることができないことが問題です。
> これでは、指定の時間になっても実行できないのがわかりますね?
> 実行する処理がループの外にあるのにもかかわらず、いつまでもループの中にいるのですから。
> 対処としては、Count=0 の下に Break を加えてくださいな。
> それでループを脱出します。

Count=0の下にループ脱出を加えました。
ですが、GenZaiとXdayが等しくなっても、ループから脱出(?)できません。
現在下記のようになっています。

       Do Until Count = 0

            If genZai = xDay Then

                Count = 0
                Exit Do
            Else

                Count = 1
            End If
            Application.DoEvents()
        Loop

うまく説明できなくて申し訳ありません。

引用返信 編集キー/
■61008 / inTopicNo.10)  Re[7]: エラー:ContextSwichDeadLock
□投稿者/ 魔界の仮面弁士 (2275回)-(2011/07/28(Thu) 22:08:57)
No61005 (ER さん) に返信
> GenZaiとXdayが等しくなっても

GenZai と Xday ではなく、
genZai と xDay ですよね。

(VB は大文字小文字を区別しませんが、質問内容を明確にするため、念のために確認)


> Count=0の下にループ脱出を加えました。
> ですが、GenZaiとXdayが等しくなっても、ループから脱出(?)できません。

一致していることをどのようにして確認されましたか?
それらが等しく無いからこそ、Exit Do しないのだと思いますよ。


> 現在下記のようになっています。

ループ中には、genZai や xDay を書き換えている箇所がありませんよね。
これでは、これらの変数はいつまでも経っても変わりませんので、脱出条件を満たせません。

(もしかしたら、DoEvents のタイミングでループ外から書き換えているのかな…とも思ったのですが、
 今回の変数はローカル変数のようですから、外部から書き換わることはありえませんしね。)


ついでに、本題以外の点についても幾つか指摘させてください。

>>> Dim Count As String
>>> Count = 1

String 変数に Integer 値を代入してしまっていますね。データ型を揃えましょう。
型の違いによる問題を防ぐため、『Option Strict On』を使う事も検討してみてください。



>>> '現在日時をセット
>>> genZai = Format(Now, "yyyyMMddHHmmss")
>>> '設定日時をセット
>>> xDay = yyyy & mm & dd & hh & nn & ss

設定日付は、Form3.TextBox1.Text などから得ているようですが、
これらの変数の桁数は保証されていますか?

たとえば午前6時に実行される場合に、hh が "06" ではなく "6" になってしまう可能性が
あるのならば、事前に入力検査を実施する必要があるかと思います。


また、OS の地域設定が和暦モードに設定されていた場合に、
yyyy の内容と genZai の年部分の書式が合致しているかも確認した方が良いでしょう。


>        Do Until Count = 0
(中略)
>             Application.DoEvents()
>         Loop
DoEvents を延々とループで呼び出し続けるのは、あまり望ましい実装ではありません。

DoEvents の繰り返さずに済むよう、Timer コンポーネントあるいは BackgrondWorker を
使ったコーディングに変更することをお奨めします。

引用返信 編集キー/
■61015 / inTopicNo.11)  Re[8]: エラー:ContextSwichDeadLock
□投稿者/ ER (4回)-(2011/07/29(Fri) 12:35:33)
No61008 (魔界の仮面弁士 さん) に返信
>設定日付は、Form3.TextBox1.Text などから得ているようですが、
>これらの変数の桁数は保証されていますか?
一桁の場合は0を加えています。

ROOPを使用すると、プログラムがとても重くなってしまうことが分かりました。
ROOPを使用せずに、等しくなるまでプログラムを待機する方法はありませんでしょうか?
Timerを使用すると良いそうなので使用してみました。
ですが、どのようなプログラムにすればいいのかが良く理解できていない状態です。
Timerについては、調べられる限り調べましたが、まだよく分かっていません。
ヒントや、コードを教え頂ければ光栄です。
引用返信 編集キー/
■61017 / inTopicNo.12)  Re[9]: エラー:ContextSwichDeadLock
□投稿者/ もく (1回)-(2011/07/29(Fri) 12:54:55)
本題から少しズレますが、
> If genZai = xDay Then
場合によってはこの判定もすり抜けるかもしれません。
何らかの要因(重い処理が別で走ってる、スレッドが一時的であれロックしてる等)で処理時間が大幅にズレたとしたら?
実際に起こるかは分かりませんが。

判定を文字列で行っていますが、DateTime型ではだめですかね?
指定日時をDateTime型へ変換しておけば毎回の文字列変換(Now -> 文字列)が無くなりますし。
(時間の差分を取るなどの演算にも転用出来たり)


No61015 (ER さん) に返信
> Timerを使用すると良いそうなので使用してみました。
> ですが、どのようなプログラムにすればいいのかが良く理解できていない状態です。

で、おそらく「指定日時になるまで待つ」という事をそのままコーディングしているのかと。
他の方々が示している内のTimerは「指定日時になった(過ぎた)か時々確認する」という事。
判定方法に多少工夫が必要になるとは思いますけど、発想の転換を。


BackgrondWorkerを使用するならマルチスレッドに関する情報も集めた方が良いでしょう。
引用返信 編集キー/
■61019 / inTopicNo.13)  Re[9]: エラー:ContextSwichDeadLock
□投稿者/ shu (891回)-(2011/07/29(Fri) 13:18:24)
No61015 (ER さん) に返信

button1をクリックして15秒間EnabledがFalseになります。

Timer1(Timerコントロール)をFormに貼り付け
Interval=100、
Enabled=False
に設定


    Private ExecTime As Date

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Timer1.Enabled = True
        ExecTime = Date.Now.AddSeconds(15)
        Button1.Enabled = False
    End Sub

    Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
        If Date.Now.Subtract(ExecTime).TotalSeconds >= 0 Then
            Timer1.Enabled = False
            '--- 処理
            Button1.Enabled = True
        End If
    End Sub

引用返信 編集キー/
■61021 / inTopicNo.14)  Re[9]: エラー:ContextSwichDeadLock
□投稿者/ 魔界の仮面弁士 (2278回)-(2011/07/29(Fri) 14:02:51)
No61015 (ER さん) に返信
> プログラムがとても重くなってしまうことが分かりました。

重くなります。そのため、今回のような目的にはループ待機は使われません。


たとえば、カップラーメンを作るために 3 分の待ち処理があるとします。
これを実世界の作業で考えてみると、待ち処理をループで実装するという事は、

 (1) 子供が親に、「もう 3 分経った?」と質問する。
 (2) 親が「まだだよ」と答えたら、子は間髪入れずに(1)に戻って再質問。
 (3) 「もういいよ」の答えとともに、子供は食べ始める。

という処理にあたります。
単純なやりとりとはいえ、これでは相当の負担となりますよね。

この質問の嵐という負担から解放される手法としては、
 ≪A案≫ キッチンタイマーを「3分後」に鳴るように仕掛けておく。
 ≪B案≫ 現在時刻の確認は連続して行わず、一定間隔(たとえば 30 秒ごと)に行う。
などが考えられますが、ここで使われるのが Timer コンポーネントです。


Timer は、一定時間が経過するごとに(≠一定時間ごとに)Tick イベントを発生させます。
この時間間隔は、Interval プロパティで指定できます。
(Interval の最大値は 2147483647 ミリ秒であり、これは約 24.8 日間に相当します)


たとえば A案の 3 分後にセットするという流れなら、こんな感じです。

Private Sub Button1_Click() Handles Button1.Click
    Button1.Enabled = False     '2度押し禁止

    Timer1.Interval = 180000    '3分=180秒=18万ミリ秒
    Timer1.Start()
End Sub

Private Sub Timer1_Tick() Handles Timer1.Tick
    Timer1.Stop()
    MessageBox.Show("3分経ったよ!")

    Button1.Enabled = True
End Sub



あるいは B 案ならこんな感じ。

    Private endTime As Date

    Private Sub Button1_Click() Handles Button1.Click
        Button1.Enabled = False     '2度押し禁止

        endTime = Now.AddMinutes(3.0R)  '終了時刻(3分後)

        Timer1.Interval = 30000     '30秒間隔で確認
        Timer1.Start()
    End Sub

    Private Sub Timer1_Tick() Handles Timer1.Tick
        If Now >= endTime Then
            Timer1.Stop()
            MessageBox.Show("3分経ったよ!")

            Button1.Enabled = True
       'Else
       '    Label1.Text = FormatDateTime(Now)
        End If
    End Sub


上記では 30 秒間隔にしていますが、たとえば Interval を 1 秒間隔にしておいて、
目標時刻になるまでは経過秒数や現在時刻を表示するようにする、といった使い方もできます。

引用返信 編集キー/
■61023 / inTopicNo.15)  Re[10]: エラー:ContextSwichDeadLock
□投稿者/ ER (5回)-(2011/07/29(Fri) 16:09:36)
No61021 (魔界の仮面弁士 さん) に返信
> ■No61015 (ER さん) に返信
>>プログラムがとても重くなってしまうことが分かりました。
>
> 重くなります。そのため、今回のような目的にはループ待機は使われません。
>
>
> たとえば、カップラーメンを作るために 3 分の待ち処理があるとします。
> これを実世界の作業で考えてみると、待ち処理をループで実装するという事は、
>
>  (1) 子供が親に、「もう 3 分経った?」と質問する。
>  (2) 親が「まだだよ」と答えたら、子は間髪入れずに(1)に戻って再質問。
>  (3) 「もういいよ」の答えとともに、子供は食べ始める。
>
> という処理にあたります。
> 単純なやりとりとはいえ、これでは相当の負担となりますよね。
>
> この質問の嵐という負担から解放される手法としては、
>  ≪A案≫ キッチンタイマーを「3分後」に鳴るように仕掛けておく。
>  ≪B案≫ 現在時刻の確認は連続して行わず、一定間隔(たとえば 30 秒ごと)に行う。
> などが考えられますが、ここで使われるのが Timer コンポーネントです。
>
>
> Timer は、一定時間が経過するごとに(≠一定時間ごとに)Tick イベントを発生させます。
> この時間間隔は、Interval プロパティで指定できます。
> (Interval の最大値は 2147483647 ミリ秒であり、これは約 24.8 日間に相当します)
>
>
> たとえば A案の 3 分後にセットするという流れなら、こんな感じです。
>
> Private Sub Button1_Click() Handles Button1.Click
> Button1.Enabled = False '2度押し禁止
>
> Timer1.Interval = 180000 '3分=180秒=18万ミリ秒
> Timer1.Start()
> End Sub
>
> Private Sub Timer1_Tick() Handles Timer1.Tick
> Timer1.Stop()
> MessageBox.Show("3分経ったよ!")
>
> Button1.Enabled = True
> End Sub
>
>
>
> あるいは B 案ならこんな感じ。
>
> Private endTime As Date
>
> Private Sub Button1_Click() Handles Button1.Click
> Button1.Enabled = False '2度押し禁止
>
> endTime = Now.AddMinutes(3.0R) '終了時刻(3分後)
>
> Timer1.Interval = 30000 '30秒間隔で確認
> Timer1.Start()
> End Sub
>
> Private Sub Timer1_Tick() Handles Timer1.Tick
> If Now >= endTime Then
> Timer1.Stop()
> MessageBox.Show("3分経ったよ!")
>
> Button1.Enabled = True
> 'Else
> ' Label1.Text = FormatDateTime(Now)
> End If
> End Sub
>
>
> 上記では 30 秒間隔にしていますが、たとえば Interval を 1 秒間隔にしておいて、
> 目標時刻になるまでは経過秒数や現在時刻を表示するようにする、といった使い方もできます。

ありがとうごさいます。
なんとか解決ができました。そして、Timerの使用法がよく分かりました。
ありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -