6

メインスレッドに潜在的に非常に遅いタスクを含む大規模な MFC ベースのアプリケーションがあります。これにより、長いタスクを実際に処理しているときに、アプリケーションがハングしたように見えることがあります。ユーザビリティの観点から、私はユーザーに進行状況についてもう少しフィードバックを提供したいと考えています。長いタスクを別々のスレッドに分割することはより良い長期的な解決策ですが、実用的な短期的な解決策は、プログレスバーとキャンセルボタンを含むダイアログを備えた独自のオブジェクトにカプセル化された新しい GUI スレッドを作成し、 CWait オブジェクトと同様の方法です。メイン スレッドは、IsCancelled メソッドを介してキャンセル ステータスを監視し、必要に応じてスローを介して終了します。

これは合理的なアプローチですか? もしそうなら、私が使用できる MFC コードが既にいくつかありますか? 最初のスケッチはこんな感じ

class CProgressThread : public CWinThread
{
public:
    CProgressThread(int ProgressMax);      
    ~CProgressThread()
    void SetProgress(int Progress);
    BOOL IsCancelled();
private:
   CProgressDialog  *theDialog;
}

void MySlowTask()
{
   CProgressThread PT(MaxProgress);
   try
   {
       {
           {  // deep in the depths of my slow task
              PT.SetProgress(Progress);
              if (PT.IsCancelled())
                 throw new CUserHasHadEnough; 
           }
        }
    }
    catch (CUserHasHadEnough *pUserHasHadEnough)
    {
        // Clean-up
    }
}    

原則として、1 つの GUI スレッドと多数のワーカー スレッドを使用する傾向がありますが、このアプローチにより、リファクタリングとテストの手間が省ける可能性があります。深刻な潜在的な落とし穴はありますか?

4

1 に答える 1

3

簡単な答え、はい、 MFC で複数の GUI スレッドを使用できます。ただし、作成したスレッド以外から GUI コンポーネントに直接アクセスすることはできません。その理由は、MFC の下の Win32 が GUI ハンドラーをスレッドごとに格納するためです。これは、あるスレッドのハンドラーが別のスレッドから見えないことを意味します。CWinThread クラスのソース コードにジャンプすると、そこにハンドラー マップ属性があります。

Windows (MFC) では、ワーカー スレッドと GUI スレッドに大きな違いはありません。GetMessage() など、メッセージに関連する最初の呼び出しの後に作成されるメッセージ キューを作成すると、任意のスレッドを GUI スレッドに変更できます。

上記のコードで、プログレス バーが 1 つのスレッドで作成され、MySlowWork() が別のスレッドで呼び出された場合。CProgressThread属性のみを使用できます。これらはすべて GUI ハンドラーを必要とするため、close、setText、SetProgress などの Win32 GUI 関連関数に触れずに使用できます。これらの関数を呼び出すと、指定されたウィンドウが見つからないというエラーが発生します。これは、そのハンドラーがスレッド ハンドラー マッピングに含まれていないためです。

GUI を変更する必要がある場合は、その進行状況バーの所有者スレッドにメッセージを送信する必要があります。PostThreadMessage を介してそのスレッド自体 (メッセージ ハンドラー) がメッセージを処理するようにします。詳細については、MSDN を参照してください

于 2013-09-20T00:37:07.527 に答える