0

win32環境でのスレッド手続きでのスタック巻き戻しについて調べてみました。
私のテストコードは次のとおりです。

class Dummy
{
public:
    Dummy() { wcout << L"dummy ctor" << endl; }
    ~Dummy() { wcout << L"dummy dtor" << endl; }
};

void InnerFunc()
{
    Dummy dm;

    while(1)
    {
        char *buf = new char[100000000];
    }
}

unsigned WINAPI ThreadFunc(void *arg)
{
    Dummy dm;

    try
    {
        InnerFunc();
    }
        catch(bad_alloc e)
    {
        wcout << e.what() << endl;
    }

    _endthreadex(0);
    return 0;
}

void OuterFunc()
{
    Dummy dm;

    HANDLE hModule;
    hModule = (HANDLE)_beginthreadex(0, 0, ThreadFunc, 0, 0, 0);
    WaitForSingleObject(hModule, INFINITE);
    CloseHandle(hModule);
}

int _tmain(int argc, _TCHAR* argv[])
{
    OuterFunc();
    wcout << e.what() << endl;

    return 0;
}

出力結果:
ダミーctor
ダミーctor
ダミーctor ダミー
dtor
割り当て不良
ダミー dtor

ご存じのとおり、コンストラクタとデストラクタの出力は対になっていません。_endthreadex() は、スレッド ハンドルにシグナルを送信し、スレッドのスタック巻き戻しをスキップすると思います。

_endthreadex() なしで再度テストしたところ、期待どおりの結果を得ることができました。

この場合、スレッドでスタックの巻き戻しが必要な場合、スレッド プロシージャで _endthreadex() を使用するべきではありませんか?

4

2 に答える 2

2

ThreadFunc で作成されたインスタンスに対してデストラクタが呼び出されることはないと思います。ただし、コンストラクタとデストラクタの呼び出しを確実に区別する方法を追加する必要があります。

それが起こっていると仮定すると、 endthreadex がスタックをクリーンアップせずにすぐにスレッドを終了することは明らかです。ドキュメントには、ThreadFunc が返されたときに endthreadex が呼び出されると明示的に記載されていますが、なぜわざわざここで明示的に呼び出すのでしょうか?

これは間違いなく、代わりに boost::thread を使用するケースです。win32 固有の詳細について心配することなく、スレッドの作成とクリーンアップに関して正しいことを行います。

于 2012-02-01T03:27:52.823 に答える
1

あなたの問題は次のとおりです。

while(1)
{
    char *buf = new char[100000000];
}

古いオブジェクトへの参照を失う新しいオブジェクトを作成するたびに、メモリリークが発生しました。

スタックの巻き戻し、そのスコープ内のすべてのローカルオブジェクトをクリアします。

Dummy dm;

は 内のローカルストレージに割り当てられたオブジェクトですInnerFunc()。Stack Unwinding はこのオブジェクトを正しく破棄し、表示される単一のデストラクタ コール トレースはこれによるものです。

スタックの巻き戻しは、動的メモリの割り当てを明示的に解除しません。で割り当てられた各ポインタは、同じアドレスで new[]a を呼び出して明示的に割り当てを解除する必要があります。delete []

それが Windows スレッド関数のいずれかとどのように関連しているかはわかりません (私は Windows にはあまり詳しくありません) が、既に述べたように、そこに問題があります。

解決策:
例外中のクリーンアップを処理する簡単な解決策はRAIIです。スマート ポインター
を 使用して生のポインターをラップする必要があります。スマート ポインターは、スコープが終了すると、オブジェクト メモリの割り当てが適切に解除されるようにします。

于 2012-02-01T03:03:38.740 に答える