我将从一个例子开始。假设我需要使用互斥锁内的函数来保护代码。有两种方法可以实现这一点。
#include <iostream>
#include <vector>
#include <pthread.h>
pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;
std::vector<float> myVec;
void threadfunc(int i, float value)
{
pthread_mutex_lock(&myMutex);
if(i <= 0 || i > myVec.size())
{
pthread_mutex_unlock(&myMutex);
return;
}
if(value < 0)
{
pthread_mutex_unlock(&myMutex);
return;
}
myVec[i] += value;
pthread_mutex_unlock(&myMutex);
return;
}
class AUTOMUTEX
{
private:
pthread_mutex_t *mMutex;
public:
AUTOMUTEX(pthread_mutex_t *mutex): mMutex(mutex)
{
pthread_mutex_lock(mMutex);
}
~AUTOMUTEX()
{
pthread_mutex_unlock(mMutex);
}
};
void threadfunc_autolock(int i, float value)
{
AUTOMUTEX autoMutex(&myMutex);
if(i <= 0 || i > myVec.size())
{
return;
}
if(value < 0)
{
return;
}
myVec[i] += value;
return;
}
int main()
{
threadfunc_autolock(5, 10);
threadfunc(0, 7);
return 1;
}
从示例中可以看出,threadfunc autolock是更好的实现,因为调用pthread_mutex_unlock函数返回由析构函数调用AUTOMUTEX来处理(C ++ 11线程支持这个。所以我们不需要我们自己的AUTOMUTEX实现如果我们使用的是C ++ 11线程库)。 有没有一种方法我们可以实现这一点,而无需每次我们需要使用一些set / reset函数对实现包装类。 boost或C ++ 11是否有一些预定义的模板类,我们可以用它来实现AUTOMUTEX对任何此类&#34; set / reset&#34;的设置。一种功能。这对于具有多个返回点的函数非常有用。 换句话说,boost / C ++提供了具有以下行为的类。
//sample code not compilable.
template <class T, class Y>
class myAuto
{
myAuto()
{
T();
}
~myAuto()
{
Y();
};
答案 0 :(得分:2)
您可以编写自己的Geneirc RAII类,例如:
class Finally
{
public:
explicit Finally(std::function<void()> f) : mF(f) {}
~Finally() noexcept() {
try
{
mF();
} catch (...) {
// Handle error.
}
}
Finally(const Finally&) = delete;
Finally(Finally&&) = delete;
Finally& operator=(const Finally&) = delete;
Finally& operator=(Finally&&) = delete;
private:
std::function<void()> mF;
};
用法:
{
pthread_mutex_lock(&myMutex);
Finally finally([&](){ pthread_mutex_unlock(&myMutex); });
//..
}
即使专用RAII对象在某些情况下可能更合适(如Mutex)。
答案 1 :(得分:0)
您可以使用ScopeGuard之类的内容。 (现在有些过时了。)
但考虑到为每种资源类型构建特定的RAII包装器是多么容易和明确,我通常会这样做。
(我认为提升并没有像ScopeGuard那样采用任何方式。使用std::function
,lambdas等等,你很容易做到。)
答案 2 :(得分:0)
有人建议将通用范围保护包含在下一个C ++标准中,我认为它已被接受。您可以找到实施here以及参考文件的链接。
原则上,它类似于传统的ScopeGuard,但它也提供了一些特殊情况,例如:用于类似C的文件API。
答案 3 :(得分:0)
编写自己的通用资源包装器有什么问题?
template <typename Res, typename Fn = std::function<void(Res*)>>
class resource_mgr
{
Res* resource;
Fn initialize, finalize;
public:
resource_mgr (Res* r, Fn i, Fn f)
: resource(r),
initialize(i),
finalize(f)
{
initialize(resource);
}
resource_mgr (resource_mgr const&) = delete;
resource_mgr (resource_mgr&&) = delete;
resource_mgr const& operator = (resource_mgr const&) = delete;
resource_mgr const& operator = (resource_mgr&&) = delete;
~resource_mgr
{
try
{
finalize(resource);
}
catch(...)
{
std::cerr << "Uh-oh!"
}
}
};
你可以保持简单,或者在这样的事情上疯狂 - 使用智能指针,定义移动操作,添加对自定义错误处理程序的支持等。你可以这样使用它:
void threadfunc_autolock(int i, float value)
{
resource_mgr<mutex_t> autoMutex (
&myMutex,
[](auto* p) { if (!pthread_mutex_lock(p)) throw Something(); },
[](auto* p) { if (!pthread_mutex_unlock(p)) throw Something(); }
);
/* . . . */
}
答案 4 :(得分:0)
以下是使用Boost.ScopeExit(未经测试)的示例:
#include <boost/scope_exit.hpp>
...
void threadfunc_autolock(int i, float value)
{
pthread_mutex_lock(&myMutex);
BOOST_SCOPE_EXIT(&myMutex) {
pthread_mutex_unlock(&myMutex);
} BOOST_SCOPE_EXIT_END
if(i <= 0 || i > myVec.size())
{
return;
}
if(value < 0)
{
return;
}
myVec[i] += value;
}