3

次のように定義されたメンバー変数があります。

HWNDWindowHandle。

変数をキャプチャしてLambdaで割り当てようとしています。そのため、コンパイラは私に警告を出し、「これ」をキャプチャするように提案しました。私はそうしましたが、ハンドルはLambda:S内でのみ有効です。つまり、Lambdaの外部ではNULLです。

class Foo
{
    private:
        HWND WindowHandle;

    public:
        Foo();
        void MakeWindow(.......);
        HWND GetWindowHandle() {return WindowHandle;};
};

Foo::Foo(){}

Foo::MakeWindow(.......)
{
    Thread = std::thread([ClassName, Title, Width, Height, this]{
                    WindowHandle = CreateWindowEx(0, ClassName.c_str(), Title.c_str(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, Width, Height, 0, 0, GetModuleHandle(NULL), 0);
                    if(WindowHandle)
                    {
                        ShowWindow(WindowHandle, SW_SHOWDEFAULT);
                        MSG msg;
                        while(GetMessage(&msg, 0, 0, 0))
                            DispatchMessage(&msg);
                    }
                });
}


int main()
{
    Foo F;
    F.MakeWindow(........);
    std::cout<<std::boolalpha<<(F.GetWindowHandle() == NULL);  //writes true.
}

上記は完全に素晴らしいウィンドウを作成します!ハンドルがnullであるだけです。ラムダ内からクラスメンバーにハンドルを取得するにはどうすればよいですか?

4

3 に答える 3

5

これは、コードに競合状態があるためです。main()で値を確認するまでに、スレッドはまだ実行されていないため、WindowHandleはまだNULLです。

実際にスレッドをまだ開始していない場合を除きます。その場合、スレッドは実行されていないため、WindowHandleはまだNULLです。

いずれにせよ、ミューテックスを使用してスレッド間でWindowHandleへのアクセスを同期する必要があります。

于 2012-12-25T15:44:19.550 に答える
0

ローカル変数、つまりラムダが作成された関数またはその引数の1つで宣言されたもののみをキャプチャできます。メンバー関数では、メンバーにアクセスするときに、メンバー関数に渡されるオブジェクトへの暗黙のポインターとしてx実際にアクセスthis->xしています。thisしたがって、ラムダはではthisなくキャプチャしxます。メンバーをキャプチャするには、そのメンバーを保持するローカル変数を作成してから、この変数をキャプチャする必要があります。例:

auto&& tmpWindowHandle = this->WindowHandle; // ... or just WindowHandle

...そしてtmpWindowHandle、ラムダ関数でキャプチャします。

ラムダ関数は同期を表示しないため、同期GetWindowHandle()も行われていないようです。呼び出し元のスレッドWindowHandleは、スレッドによって設定される前にメンバーにアクセスする可能性があります。何らかの形式の同期が必要です。または、他のスレッドからjoin()useを呼び出す前に、何らかの形式のmutexexまたは条件変数を使用します。WindowHandle全体的なセットアップは、次の優れたアプリケーションのように見えますstd::future<...>。これは、関数を潜在的に同時に実行し、結果が実際にアクセスされるときに結果が必要になるまでブロックすることを目的としています。

于 2012-12-25T15:44:48.910 に答える
0

WindowHandle別のスレッドに割り当てています。したがって、おそらく何が起こるかというと、新しいスレッドがまだ開始されておらず、WindowHandleすでに変更されているかどうかを確認しているということです。WindowHandleまた、ミューテックスまたは他の構成でアクセスを保護する必要があります。そうしないと、競合状態になります。

于 2012-12-25T15:45:37.397 に答える