类和互斥体

Joe*_*res 6 c++ multithreading mutex c++11

假设我有一个类代表一些名为 foo 的数据结构:

\n\n
class foo{\n  public:\n    foo(){\n      attr01 = 0;\n    }\n    void f(){\n      attr01 += 5;\n    }\n  private:\n    int attr01;\n};\n\nclass fooSingleThreadUserClass{\n    void usefoo(){\n      fooAttr.f();\n    }\n\n    foo fooAttr;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在假设在软件构建的后期,我发现我需要多线程。我应该在 foo 中添加互斥体吗?

\n\n
class foo{\n  public:\n    foo(){\n      attr01 = 0;\n    }\n    void f(){\n      attr01Mutex.lock();\n      attr01 += 5;\n      attr01Mutex.unlock();\n    }\n  private:\n    int attr01;\n    std::mutex attr01Mutex;\n};\n\nclass fooMultiThreadUserClass{\n    void usefoo(){\n      std::thread t1(&fooMultiThreadUserClass::useFooWorker, this);\n      std::thread t2(&fooMultiThreadUserClass::useFooWorker, this);\n      std::thread t3(&fooMultiThreadUserClass::useFooWorker, this);\n      std::thread t4(&fooMultiThreadUserClass::useFooWorker, this);\n\n      t1.join();\n      t2.join();\n      t3.join();\n      t4.join();\n    }\n\n    void useFooWorker(){\n      fooAttr.f();\n    }\n\n    foo fooAttr;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我知道 fooMultiThreadUserClass 现在能够在没有竞争的情况下以高性能运行 foo,但是 fooSingleThreadUserClass 会因为互斥开销而降低性能吗?我很想知道。或者我应该出于并发目的从 foo 派生 fooCC,以便 fooSingleThreadUserClas 可以继续使用没有互斥锁的 foo,而 fooMultiThreadUserClass 使用带有互斥锁的 fooCC,如下所示

\n\n
class fooCC : public foo{\n  public:\n    foo(){\n      attr01 = 0;\n    }\n    void f(){  // I assume that foo::f() is now a virtual function.\n      attr01Mutex.lock();\n      foo::f();\n      attr01Mutex.unlock();\n    }\n  private:\n    std::mutex attr01Mutex;\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

还假设编译器优化已经处理了虚拟调度。我想知道是否应该使用继承或简单地将互斥锁放在原始类中。

\n\n

我已经在 Stackoverflow 上进行了搜索,但我想我的问题有点太具体了。

\n\n

编辑:注意,\xe2\x80\x99t 不必只有一个参数,这个问题应该是抽象的,具有一类 n 参数。

\n

小智 5

使用std::lock_guard. 在其构造函数中lock_guard采用 a 。mutex在施工过程中,lock_guard锁定mutex。当lock_guard超出范围时,其析构函数会自动释放锁。

class foo
{
private:
  std::mutex mutex;
  int attr01;

public:
  foo() {
    attr01 = 0;
  }

  void f(){
    std::lock_guard<std::mutex> lock (mutex);
    attr01 += 5;
  }
};
Run Code Online (Sandbox Code Playgroud)

如果您需要能够锁定或解锁from功能,您可以添加mutable。我通常会保留直到我特别需要它为止。mutexmutexconstmutablemutex

会损失性能吗?这取决于。如果您调用该函数一百万次,那么创建该函数的开销可能mutex会成为一个问题(它们并不便宜)。如果函数执行时间较长,并且被多个线程频繁调用,那么快速阻塞可能会影响性能。如果您无法查明具体问题,只需使用std::lock_guard.

汉斯·帕桑特提出了一个超出你问题范围的合理担忧。我认为赫伯·萨特(Herb Sutter)(?)在他的一篇网站文章中写到了这一点。不幸的是我现在找不到它。要理解为什么多线程如此困难,以及为什么单个数据字段上的锁“不够”,请阅读有关多线程编程的书,例如《C++ Concurrency in Action: Practical Multithreading》

  • http://herbsutter.com/2014/01/13/gotw-95-solution-thread-safety-and-synchronization/? (2认同)