将多线程类重构为单线程+多线程类

Refactoring a multithreaded class into a single threaded + a multithreaded

本文关键字:多线程 单线程 重构      更新时间:2023-10-16

我有一个这样实现的多线程c++类:

class MyClass{
protected:
  somemutex mutex; 
  void _unsafeMethod(){...};
public:
  void safeMethod{
    locker lock(mutex);
    _unsafeMethod();
  }
}

我很高兴,但注意到,在大多数情况下,多线程支持并不是真正必要的,所以我想把它分成两个类:一个线程安全的,和一个不安全的,但性能更好的。

问题是,有成千上万行代码使用类,所以我需要保持接口相同。当然,类名将在其定义中更改,这取决于它是否需要支持MT。

我的想法是这样的:

class MyClass{
protected:
  void _unsafeMethod(){...};
public:
  virtual void safeMethod{
    _unsafeMethod()
  };
};
class MyThreadSafeClass: public MyClass{
protected:
  somemutex mutex; 
public:
  virtual void safeMethod{
    locker lock(mutex);
    _unsafeMethod();
  };
}

这里的问题是虚函数调用:它是否使执行速度变慢,所以我立即失去了单线程类性能改进的好处?从第一个测试中,它看起来像

解决方案B

class MyClass{
protected:
  somemutex * pmutex;
  void _unsafeMethod(){...};
public:
  MyClass( bool isthreadsafe ){
    if( isthreadsafe )
       pmutex = new somemutex();
    else
       pmutex = NULL;
  };
  void safeMethod{
    if( pmutex )
    {
       locker lock(*pmutex);
       _unsafeMethod();
    }
    else
      _unsafeMethod();
  };
}

第二个解决方案看起来很脏,并且在每个要解析的调用中总是有一个'if'。

你认为哪个解决方案更有效?你有更好/更干净/更有效的解决方案吗?

非常感谢!

一个简单的答案是将模板MyClass设置为互斥锁类型:

template <typename MutexType>
class MyClass{
protected:
  MutextType mutex; 
public:
  void safeMethod{
    locker lock(mutex);
    // stuff
  }
}

然后你可以用一个真正的互斥锁或一个无操作的互斥锁实例化它来获得你想要的行为。

您可以使用装饰器模式或包装器。

A]一个修改过的包装器,这样你就可以使用虚函数了:

class MyClass{
protected:
  void _unsafeMethod(){};
};
class MyThreadSafeClass{
protected:
  somemutex mutex; 
  MyClass& myclassRef;
public:
    MyThreadSafeClass(MyClass& myclass):myclassRef(myclass){}
  void safeMethod(){
    locker lock(mutex);
    myclassRef._unsafeMethod();
  }
};

类调用:

MyClass myclass;
MyThreadSafeClass mythreadsafeclass(myclass);
mythreadsafeclass.safeMethod();

B]一个带有虚拟接口的装饰器:

class MyClassInterface{
public:
  virtual void Method()=0;
};
class MyClass : public MyClassInterface{
protected:
  virtual void Method() override{};
};
class MyThreadSafeClass: public MyClassInterface{
protected:
  somemutex mutex; 
  MyClassInterface& myclassRef;
public:
    MyThreadSafeClass(MyClassInterface& myclass):myclassRef(myclass){}
   virtual void Method() override{
     locker lock(mutex);
     myclassRef.Method();
  }
};

可以将互斥锁作为参数传递给构造函数。这将允许您选择锁定机制,而不必为您希望的每种锁定类型修改或复制实现。

class Mutex
{
public:
    virtual void Lock() = 0;
};
class MyClass
{
protected:
    Mutex&   mutex;
public:
    MyClass(Mutex& m) : mutex(m) {}
    void Lock()
    {
        mutex.Lock();
    }
};