2009-08-18 21 views
2

私は現在、すべてのサブコンポーネントが同期して初期化されるという仮定から生じる初期化の問題を解決しようとしています。非同期コンポーネントを同期させることはできますか?

UIは独自のUIを持つクラスをインスタンス化します。それは次のようになります。

ConfWizard cf = new ConfWizard(); 
cf.ShowDialog(); 

トラブルがConfWizardクラスは非同期的に初期化し、別のクラスを使用していますが、ShowDialogをが正しく機能するために呼び出される前に準備ができていなければならないということです。 ReadyEventが発生する直前に、現在のコンストラクタは、一般的に正しく初期化しないまでヘルパーのプロパティを設定することはできませんので

public ConfWizard() 
{ 
    helper = new HelperClass 
    helper.ReadyEvent += new HelperClass.ReadyEventHandler(this.helper_ReadyEvent) 
    helper.StartUp(); 
    // Do more initialization using properties of hc 
} 

private helper_ReadyEvent() 
{ 
    //HelperClass is ready to use 
} 

:ConfWizardコードは次のように見えます。残りの初期化をhelper_ReadyEventに入れるのは明らかですが、コンストラクタがオブジェクトを使用できるようになる前に戻すことになります。 ConfWizardオブジェクトを使用するクラスは、コンストラクタがオブジェクトを完全に使用できるように戻すと仮定しているため、早期返却は望ましくありません。

残念ながら私はHelperClassを変更できないため、何らかの理由でConfWizardクラスを同期して使用できるように非同期動作をマスクする必要があります。

(イベントハンドラでSetを呼び出す)ManualResetEventオブジェクトを使用しようとしましたが、WaitOneの呼び出しがブロックされているため、イベントがアプリケーションをハングして処理されません。

.NET1.1でこれを達成する方法についてのアイデアはありますか?

UPDATE - Aug 21、2009
今日は実験​​する時間がありましたが、ここに私が見つけたものがあります。

WaitOne - アプリケーションを停止するだけで、十分なタイムアウトが毎回有効になります。残念なことに、タイムアウトは少なくとも5秒(私が待つ気にかない)以上にする必要があります。タイムアウトがなければ、それでもハングアップします。セットを呼び出すイベントは決して起こらない。

スリーピング - WaitOneと同じですが、タイムアウトが十分に長くなると動作するように見えます。

スレッディング - UIの動作が初期化の結果によって変更されるため、初期化が完了するまでUIを継続しないようにします。ただし、HelperClassオブジェクトの初期化を別のスレッドに分割し、Thread.Joinを呼び出してメインスレッドを一時停止させます。

問題への解決策は、正しい方法で複数のスレッドを使用しているようです。

答えて

-1

なぜ接続しないのですか?

helper.StartUp();

to the helper.ReadyEventも同様ですか?

+1

?それは意味をなさないか、または私の脳は今日完全に揚げられています.... –

1

helper_ReadyEventデリゲートが呼び出されるたびにtrueに設定されている設定ウィザードで、ハッキングして読み取り専用プロパティを追加します。次にフォームを準備したら、プロパティをポーリングしてダイアログを表示できます。

ConfigWizard wiz = new ConfigWizard(); 
while (!wiz.Ready) System.Threading.Thread.Sleep(2000); 
wiz.ShowDialog(); 

または、ConfigWizardを初期化する前にヘルパークラスを初期化できませんでしたか?次に、クラスコンストラクタを介してコンフィグフォームに初期化されたヘルパークラスへの参照を提供することができますか?ここでの回答の数を考えると、あなたがその課題を達成する方法はたくさんあるようです。

0

ManualResetEventがあなたのケースでどのように機能しないのか分かりません。 HelperClassインスタンスを作成してReadyEventSetというインスタンスを作成した場合は、ConfWizardコンストラクタの末尾にWaitOneを追加するだけです。はい、WaitOneはブロックされますが、これは動作です(あなたのConfWizardコンストラクタはすべて準備が整うまで戻りません)。

+0

ブロックの振る舞いは私が欲しいものです。残念ながら、メインスレッドでWaitOneを呼び出すと、メッセージポンプもブロックされ、ReadyEventが処理されるのを防ぐことができます。つまり、Setは決してコールされず、アプリケーションはハングします。 – Corin

+0

UIスレッドで 'ConfWizard'を初期化する必要がありますか?バックグラウンドスレッドに初期化を委任できないので、UIスレッドはUI関連のタスクを続行することができますか? – paracycle

0

私の最初の考えは、「待機ハンドルを使用する」でしたが、あなたの投稿の最後に言ったように、イベントはUIスレッドで発生しようとしますが、 UIスレッドで

(私はそれが動作しない理由、これがあると仮定し、それがバックグラウンドスレッドで発生させた場合 - 。。ただUIが、それは準備のスレッド合図するManualResetEventを使用)

一つの代替ソリューションは、フォームのショーを聞かせてあり、ヘルパークラスの準備ができていない、そしてそれは準備ができたときに処理を受けるアクションのキューにヘルパークラス上のすべてのアクションをリダイレクトしても:次に

private Queue actions = new Queue(); 

public void DoSomethingToHelper() 
{ 
    if(!helperClass.IsReady()) 
    { 
     Action work = new Action(DoSomethingToComponent); 
    } 
    else 
    { 
     // Real work here. 
    } 
} 

それは準備ができたとき、あなたはすべてのプロセスを通過して行きますアクション:

private helper_ReadyEvent() 
{ 
    foreach (Action action in actions) 
    { 
     action.Invoke(); 
    } 
    actions.Clear(); 
} 
0

私はManualResetEventオブジェクト(イベントハンドラでSetを呼び出す)を使用しようとしましたが、WaitOneへの呼び出しがブロックされているため、イベントはアプリケーションをハングアップしません。

これは、ctorがオンになっている同じスレッドでReadyEventが呼び出されているか、HelperClassにUIスレッドが必要であることを意味する必要があります。これはややこしいものです。コンストラクタが本当に遅れることはありません。

HelperClassがウィンドウメッセージを処理するだけであれば、そこにApplication.DoEventsコールを挿入できます。

class ConfWizard { 
    private ManualResetEvent _init = new ManualResetEvent(false); 

    public ConfWizard() { 
     var h = new HelperClass(); 
     h.ReadyEvent += this.helper_ReadyEvent; 
     h.StartUp(); 

     do { 
      Application.DoEvents(); 
     } while (!_init.WaitOne(1000)); 
    }  

    private void helper_ReadyEvent() { 
     _init.Set(); 
    } 
} 

class HelperClass { 
    public event Action ReadyEvent; 

    public void StartUp() { 
     ThreadPool.QueueUserWorkItem(s => { 
     Thread.Sleep(10000); 
     var e = this.ReadyEvent; 
     if (e != null) e(); 
     }); 
    } 
} 

は、そうでなければ - 私はあなたが工場を通じて作成を非同期、またはちょうどHelperClassは準備ができていない可能性があるという事実に対処し、再処理や必要に応じてUIを無効にする必要がありますどちらかと思います。

編集:

は[DoEvents関数]それはVB6にあったと同じくらい怖いですか?

manypeople,yes。しかし、IMO、それは(いつものように)シナリオに依存します。 doは再入可能性があるため注意が必要です。ウィンドウメッセージの結果として実行している場合は、それを防ぐ必要があります。

FWIW、DoEventsの最も一般的な使い方は、UIをハングするような長時間実行されるオペレーションのために画面を再描画することです。その場合、.NETはスレッド処理でより良い処理方法を提供します。しかし、UIスレッド(あなたが行っている)を生成したいだけの場合は、私は少し注意深く配置されたDoEvent呼び出しで問題はありません。そして、率直に言って、それはあなたの選択肢の中で最も複雑ではないと思います(HelperClassの書き換えが不十分です)。

+0

私はDoEventsのようなものを考えましたが、それはVB6の一部であり、.NETに変換されなかった可能性があると考えていました。 VB6と同じくらい恐ろしいですか? – Corin

関連する問題