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 之前调用它们吗?为什么不在启动任何线程之前将它们称为 main 中的第一件事呢?

否则:经典习惯用法是在静态变量的初始化程序中使用它们。通常的方法是从构造函数中调用它们;如果您有必须初始化的附加数据,这无疑是最好的方法。如果没有,那么简单的事情就是:

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

会成功的。

形式上,这仅保证它们将在使用同一翻译单元中的任何其他内容之前被初始化,但实际上,这将保证函数在 main 之前调用,或者在加载 DLL 期间(如果它在 DLL 中)除了主要的那个。

于 2013-02-21T22:59:36.427 回答
2

如果您使用的是 C++11,请记住:

  1. 静态函数变量初始化是线程安全的。
  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() 之前初始化函数的原始方法,您可以使用全局变量初始化,因为它发生在 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 回答