在退出功能之前调用一个函数

时间:2015-10-09 06:27:47

标签: c++ c++11 boost

我将从一个例子开始。假设我需要使用互斥锁内的函数来保护代码。有两种方法可以实现这一点。

#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();
};

5 个答案:

答案 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;
}