我可以使C ++ 11类/对象通用线程安全吗?

时间:2017-09-02 08:11:54

标签: c++ multithreading

阅读Can mutex implementations be interchanged (independently of the thread implementation)后,我的理解是,通过使用C ++ 11互斥锁,我可以确保我的类对所有线程实现的线程安全

我的理解是否正确?我期待是(可能有警告)或不(有原因)。

  • 我的代码可能需要在目标平台上重新编译,但我的源代码不需要进行任何更改。 (@Peter)
  • 或者说,我应该能够为特定平台编译并提供可以安全地与任何线程库一起使用的.so吗?

鉴于投票率下降,我会尝试更精确。

任何其他线程API的互斥锁独立的C ++ 11实现? C ++ 11互斥体只能相互了解并实现阻塞,而与执行线程如何达到这一点无关。

C ++ 11互斥体是否总能与OpenMP一起使用(重新编译)?团队A可以提供线程安全的API(使用C ++互斥体)供团队B使用,无论团队B使用哪种特定的线程API?所有代码都可以重新编译。

我附上了一个有效的例子。

#include <iostream>
#include <omp.h>
#include <mutex>
class A {
    unsigned n = 0;

public:

    void inc() {
        ++n;
    }

    unsigned get() {
        return n;
    }
};

class B {
    std::mutex mutex;
    unsigned n = 0;

public:

    void inc() {
        mutex.lock();
        ++n;
        mutex.unlock();

    }

    unsigned get() {
        return n;
    }
};

int main() {

    A a;
    B b;
#pragma omp parallel for
    for (int i = 0; i < 100000; i++) {
        a.inc();
        b.inc();
    }

    std::cout << a.get() << " " << b.get() << std::endl;

}

我上次参加的输出是:

98015 100000

这是运气还是设计?

2 个答案:

答案 0 :(得分:2)

如果您将所有成员设为私有且对所有同步机制(std::mutexstd::atomic保护的数据进行访问(读/写)操作,则可以使您的类平台独立于线程安全,或其他来自boost / Qt / whatever),无论使用何种线程API。

最简单的方法是在类中使用单个std::recursive_mutex / std::unique_lock对进行所有数据访问操作(getter / setter),并使数据成员保持私有。无论线程API如何,它都可以保证工作,但在性能方面可能不是最佳的。

大多数其他解决方案可能适合您的具体情况。有时根本不需要同步原语。

答案 1 :(得分:1)

您始终可以使用互斥锁使类的成员函数在没有数据争用的情况下进行交互。但这还不足以确保可以从多个线程中使用对象而不会发生冲突;你需要更广泛的设计。例如,考虑写出向量的内容:

int size = vec.size();
for (int i = 0; i < size; ++i)
    std::cout << vec[i] << ' ';
std::cout << '\n';

使用内部互斥锁时,对vec.size()的调用和对vec::operator[]的调用没有数据争用,因此从多个线程调用它们是“安全的”。但是这段代码有一个问题:如果另一个线程从向量中移除了一个元素,那么向量将比它小,并且这个循环将在最后运行。