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

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

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

Re[2]: バックグランドワーカーとグローバル変数


(過去ログ 136 を表示中)

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

■80073 / inTopicNo.1)  バックグランドワーカーとグローバル変数
  
□投稿者/ 初心者123 (1回)-(2016/06/08(Wed) 20:41:39)

分類:[C#] 

はじめましてバックグランドワーカ、C#初心者です。よろしくお願い致します。
環境はVS2013 C# WindowsFormアプリケーションです。

メインフォームとBGWスレッドの間でデータ受け渡しが多いため、
グローバル変数でやり取りすることを考えており、BGW使い方を含めて基礎動作の確認を行っております。

メイン側でグローバル変数、変数1、変数2を定義し、
メインフォームのタイマーで変数1を加算しています。
BGWスレッドで変数1の値を比較し変数2の計算を行っているのですが
計算結果が期待した値になりません。
実際はこのような処理ではないですが、現象再現のため簡略化したプログラムが下記になります。
実際はもっと多くのデータやり取りですが、基本的には変数操作はBGW側で行い、
メイン側はほとんどが表示や参照だけであるため排他制御の必要もないと考えております。
基本的な問題かと思いますが御教授願います

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    
    public partial class Form1 : Form
    {

        long Cnt1 = 0;   // 変数1
        long Cnt2 = 1;   // 変数2

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            timer1.Enabled = true;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Cnt1++;   // メインフォームのタイマーで変数1を加算
        }

        
        private void btnBGWSta_Click(object sender, EventArgs e)
        {
            bgW1.RunWorkerAsync();    
        }
        
        private void btnBGWStp_Click(object sender, EventArgs e)
        {
            bgW1.CancelAsync();        
        }

        //=================================================================================
        // BGW Main
        //=================================================================================
        private void bgW1_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                if (bgW1.CancellationPending)
                {
                    e.Cancel = true;
                    break;            
                }
                if (Cnt1 == 100)         // 変数1の値を比較
                {
                    Cnt2 = Cnt2 * 2;     // 変数2を計算 初期値1であるため結果2を期待しているが2048になる
                }
                System.Threading.Thread.Sleep(1);
            }
        }

    }
}

引用返信 編集キー/
■80075 / inTopicNo.2)  Re[1]: バックグランドワーカーとグローバル変数
□投稿者/ Jitta (197回)-(2016/06/08(Wed) 20:51:19)
No80073 (初心者123 さん) に返信
Cnt1が100である時間が8秒あるから。
1度2倍したら、次のトリガーまでifの条件が成立したらいけないよね。

引用返信 編集キー/
■80078 / inTopicNo.3)  Re[1]: バックグランドワーカーとグローバル変数
□投稿者/ shu (884回)-(2016/06/08(Wed) 21:23:15)
No80073 (初心者123 さん) に返信

https://msdn.microsoft.com/ja-jp/library/d00bd51t(v=vs.110).aspx

Sleepの引数はms単位なので
1msスリープしたらループを回るので
Timer1_tickが発生するまでの間条件が変わらない状態となります。

別にフラグなど設けるなどして繰り返し足されるのを抑制する必要があります。
引用返信 編集キー/
■80079 / inTopicNo.4)  Re[1]: バックグランドワーカーとグローバル変数
□投稿者/ なちゃ (118回)-(2016/06/08(Wed) 22:06:49)
やや別の観点から。
スレッド間で正しく変数を共有するには、それなりにルールがあります。
仮に今のプログラムがロジック的には正しかったとしても、スレッド感では正しい共有の仕方をしないと、正しく動作する保証はなくなります。

例えば、タイマーで加算した変数の値がバツマクグラウンドスレッド側で見えないなど。

現実には.NETの場合、あまりこういうことは起こりにくい実装にはなっていますが、正しい方法を知っておくに越したことはありません。
たとえば今の実装では、おそらくバックグラウンドワーカーへのアクセスでメモリ同期が働いてうまく動作します。
が、ある意味たまたまのようなもので、それに依存するのは望ましくはありません。
※その前にSleepがきいてると思いますが、これはなくなったりする想定で
引用返信 編集キー/
■80080 / inTopicNo.5)  Re[2]: バックグランドワーカーとグローバル変数
□投稿者/ 初心者123 (2回)-(2016/06/08(Wed) 22:12:16)
No80075 (Jitta さん) に返信
> ■No80073 (初心者123 さん) に返信
> Cnt1が100である時間が8秒あるから。
> 1度2倍したら、次のトリガーまでifの条件が成立したらいけないよね。

どうもありがとうございます。気付きました。BGWに何かあるのかとかばかり考えていました。
解決済み
引用返信 編集キー/
■80081 / inTopicNo.6)  Re[2]: バックグランドワーカーとグローバル変数
□投稿者/ 初心者123 (3回)-(2016/06/08(Wed) 22:13:03)
No80078 (shu さん) に返信
> ■No80073 (初心者123 さん) に返信
>
> https://msdn.microsoft.com/ja-jp/library/d00bd51t(v=vs.110).aspx
>
> Sleepの引数はms単位なので
> 1msスリープしたらループを回るので
> Timer1_tickが発生するまでの間条件が変わらない状態となります。
>
> 別にフラグなど設けるなどして繰り返し足されるのを抑制する必要があります。

どうもありがとうございます。気付きました。BGWに何かあるのかとかばかり考えていました。
解決済み
引用返信 編集キー/
■80082 / inTopicNo.7)  Re[2]: バックグランドワーカーとグローバル変数
□投稿者/ なちゃ (119回)-(2016/06/08(Wed) 22:14:51)
因みにバックグラウンドワーカーへのアクセスでメモリ同期が発生するのは、キャンセル通知は当然最新値を確実に取得する必要があるので、それを保証する実装になっているからですが、多分その実装はバックグラウンドワーカーがMarshalByRefObjectの派生クラスであることに依存する(というか利用する)仕組みになってた気がします。

何言ってるのかわからないマニアックな話ですね。
引用返信 編集キー/
■80083 / inTopicNo.8)  Re[2]: バックグランドワーカーとグローバル変数
□投稿者/ 初心者123 (4回)-(2016/06/08(Wed) 22:17:49)
No80079 (なちゃ さん) に返信
> やや別の観点から。
> スレッド間で正しく変数を共有するには、それなりにルールがあります。
> 仮に今のプログラムがロジック的には正しかったとしても、スレッド感では正しい共有の仕方をしないと、正しく動作する保証はなくなります。
>
> 例えば、タイマーで加算した変数の値がバツマクグラウンドスレッド側で見えないなど。
>
> 現実には.NETの場合、あまりこういうことは起こりにくい実装にはなっていますが、正しい方法を知っておくに越したことはありません。
> たとえば今の実装では、おそらくバックグラウンドワーカーへのアクセスでメモリ同期が働いてうまく動作します。
> が、ある意味たまたまのようなもので、それに依存するのは望ましくはありません。
> ※その前にSleepがきいてると思いますが、これはなくなったりする想定で

必要に応じて排他をかけたり、シェイクハンドするかとは思いますが、
今回はそれ以前の問題でした。どうもありがとうございます。
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -