在现代 C++ (C++17) 中,函数看起来像
template <typename Mutex, typename Func, typename... Args>
decltype(auto) doMutexProtected(Mutex& mutex, Func&& func, Args&&... args)
{
std::unique_lock lg(mutex);
return std::forward<Func>(func)(std::forward<Args>(args)...);
}
这会将互斥锁锁定在 RAII 类型中,因此所有退出路径都会释放互斥锁,然后完美地转发函数,并且它的参数返回与 func 返回的确切类型。
现在,由于您不能使用现代 C++,我们必须尽可能多地尝试实现上述功能,并且有几种方法可以解决问题。实现std::unique_lock 非常简单。根据您想要的功能,它可以很简单
template <typename Mutex>
class my_unique_lock
{
public:
unique_lock(Mutex& mutex) : mutex(mutex) { mutex.lock(); }
~unique_lock() { mutex.unlock(); }
private:
Mutex& mutex;
unique_lock(unique_lock const&); // make it non copyable
};
这样就可以解决 25% 的问题 :)。不幸的是,这是最简单的部分。由于C++98/03没有decltype(auto),甚至没有decltype或auto,我们需要想出一种不同的方法来获取返回类型。我们可以将其设为void 并使用输出参数,这意味着您在调用函数时不需要指定任何内容,但这意味着您无法获得对返回内容的引用。以必须指定您想要的返回类型为代价,您可以拥有类似的功能
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func func, Arg1 arg1)
{
my_unique_lock<Mutex> lg(mutex);
return func(arg1);
}
你会这样称呼它
T foo = doMutexProtected<T>(mutex, func, arg);
T& bar = doMutexProtected<T&>(mutex, func, arg);
由于 C++98/03 没有可变参数模板,你不得不为不同数量的参数添加一堆重载,你必须决定在哪一点足够的参数是足够的,即:
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func func, Arg1 arg1) {...}
template <typename Ret, typename Mutex, typename Func, typename Arg1, typename Arg2>
Ret doMutexProtected(Mutex& mutex, Func func, Arg1 arg1, Arg2 arg2) {...}
template <typename Ret, typename Mutex, typename Func, typename Arg1, typename Arg2, typename Arg3>
Ret doMutexProtected(Mutex& mutex, Func func, Arg1 arg1, Arg2 arg2, Arg3 arg3) {...}
...
然后你必须处理引用。现代版本完美地转发了所有内容(除非Func 要求,否则不会复制任何内容)。我们不能在 C++98/03 中这样做,所以我们必须添加所有的引用排列,这样我们就不会像第一个版本那样制作不必要的副本。这意味着
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func func, Arg1 arg1)
确实需要
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func& func, Arg1& arg1) {...}
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func const& func, Arg1& arg1) {...}
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func& func, Arg1 const& arg1) {...}
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func conts& func, Arg1 const& arg1) {...}
当您添加更多参数时,它会膨胀。
如果您不想自己做所有这些,我相信Boost 至少已经为 C++03 完成了部分工作,您可以使用它们的实用程序。