0

私の目標は、特定の関数が 2 つの別々のスレッドで同時に呼び出された場合に問題を引き起こす可能性があるさまざまな競合状態にすばやく対処することです。私のクイックフィックスは、関数が main() の前に呼び出されることによって初期化されていることを保証することです。これは私が思いついた解決策ですが、車輪を再発明する可能性が高いと感じています. MSVC2010 STL で既に利用可能なオプションはありますか? (ブーストはまだありません)または、この状況で各関数に重要なスレッドセーフコードを追加することなく、これらの問題に迅速に対処するより良い方法があるでしょうか?

template <typename T, T func>
struct PreLoaderHelper
{
    PreLoaderHelper()
    {
        wcout << L"Preload helper constructor" << endl;
        func();
    }
};

template <typename T, T func>
struct PreLoader
{
    static PreLoaderHelper<T, func> _helper;
};

template <typename T, T func>
PreLoaderHelper<T, func> PreLoader<T, func>::_helper;

#define PRELOAD(fn) template struct PreLoader<decltype(&fn), fn>; 

void foo() { wcout << L"inside foo" << endl; }
void bar() { wcout << L"inside bar" << endl; }
vector<wstring> & foobar() 
{ 
    static vector<wstring> sPresidents;
    if(sPresidents.size() == 0)
    {
        sPresidents.push_back(L"George Washington");
        sPresidents.push_back(L"John Addams");
        sPresidents.push_back(L"Thomas Jefferson");
    }
    return sPresidents;
}
wstring foofoo(const wstring &) { wcout << L"inside foofoo" << endl; return L"foofoo";}

PRELOAD(foo);
PRELOAD(bar);
PRELOAD(foobar);
PRELOAD(foo);

int main()
{
    return 0;
}
4

4 に答える 4

3

あなたはこれを行うことができます:

int dummy = (foo(), (void)0, bar(), 0);

int main() 
{
    // foo() and bar() have already been called
}

さらに、C++11 は、次のバリアントが単一の呼び出しのみを引き起こし、競合がないことを保証します。

void call_foo()
{
    static int dummy = (call_foo(), 0);
}

void some_thread_function() { call_foo(); }
于 2013-02-21T22:59:31.307 に答える
3

最初の質問: main に入る前に本当にそれらを呼び出す必要がありますか? スレッドを開始する前に、メインで最初にそれらを呼び出さないのはなぜですか?

それ以外の場合: 古典的なイディオムは、静的変数への初期化子でそれらを使用することです。通常の方法は、コンストラクターから呼び出すことです。初期化する必要がある追加のデータがある場合、これが間違いなく最良の方法です。そうでない場合は、次のように簡単です。

static bool initialized = (function(), true);

トリックを行います。

正式には、これは、同じ翻訳単位内の他のものが使用される前に初期化されることを保証するだけですが、実際には、関数が main の前、または DLL 内にある場合は DLL のロード中に呼び出されることが保証されます。メインのもの以外。

于 2013-02-21T22:59:36.427 に答える
2

C++11 を使用している場合は、次のことを覚えておいてください。

  1. static 関数変数の初期化はスレッドセーフです。
  2. リストの初期化セマンティクスを使用できます。

試す:

std::vector<std::wstring>& plop1()
{
    // Thread safe
    // Guaranteed to be done once
    // No setup required
    // No cost if not used.
    static std::vector<std::wstring> sPresidents =
    {   
        L"George Washington",
        L"John Addams",
        L"Thomas Jefferson"
    };  
    return sPresidents;
}
于 2013-02-22T01:11:55.090 に答える
0

状況に応じて、クリティカル セクションを使用して適切な同期を使用することを強くお勧めします。クリティカル セクションに出入りすることで多くのコードが追加されることはなく、状況を適切に処理できます。

main() の前に関数を初期化するという元のアプローチを続行したくない場合は、メイン関数呼び出しの前に発生するグローバル変数の初期化を使用できます。このアプローチに関する素晴らしい記事が次の場所にあります。

http://blog.fishingcactus.com/index.php/2009/01/28/fixing-c-static-and-global-variable-initialization/#sthash.pmBtrYD8.dpbs

于 2013-02-21T22:59:34.030 に答える