如果mutex由成员管理,您是否需要mutex用于类/结构?

时间:2016-09-15 15:59:58

标签: c++ class mutex

因此,如果我通过线程之间的引用/指针传递变量,我应该实现互斥或使用std :: atomic(我知道还有其他选项)。但是,如果我传递一个包含std :: atomic成员或具有相应互斥成员并希望访问成员变量的类呢?

示例:

//class.h
#include<mutex>
#include<atomic>
class MyClass {
    Public:
        std::atomic<int> i;
        double d;
        std::mutex dmutex;
        MyClass();
    Private:
        ~MyClass();
}


//main.cpp
#includ<mutex>
#include "class.h"

void ThreadFunction (MyClass &myclass) {
    for (i = 0; i < 100; i++) {
        myclass.i++;
        myclass.dmutex.lock();
        myclass.d += 0.5;
        myclass.dmutex.unlock();
    }
    return;
}

int main () {
    MyClass commonclass;
    std::thread t_thread1 (ThreadFunction, commonclass);
    std::thread t_thread1 (ThreadFunction, commonclass);
}

OR

//main.cpp
#includ<mutex>
#include "class.h"

void ThreadFunction (MyClass &myclass, std::mutex &mymutex) {
    for (i = 0; i < 100; i++) {
        mymutex.lock();
        myclass.i++;
        myclass.d += 0.5;
        mymutex.unlock();
    }
    return;
}

int main () {
    MyClass commonclass;
    std::mutex commonmutex;
    std::thread t_thread1 (ThreadFunction, commonclass, commonmutex);
    std::thread t_thread2 (ThreadFunction, commonclass, commonmutex);
    t_thread1.join();
    t_thread2.join();
}

让我们谈谈只访问成员变量(我现在关注)然后成员函数,假设他们修改这些成员变量并相应地处理静音。一个比另一个更正确吗?第二个不必要吗?

2 个答案:

答案 0 :(得分:1)

你在这里混合:使用东西作为公共成员不会改变任何东西。您只是在指针参与方面采取了额外的方法。

我说到了本质:如果两个线程正在改变本身不是原子的数据,它们必须通过例如互斥锁进行同步。 这两种情况都与同步有关。

补充:更好地考虑操作:更改非原子变量是机器代码中的多个操作。 std::atomic仅仅通过例如使用特殊机器指令来比较和改变一个原子机步骤中的值来帮助提供通常的或者似乎是原子的操作。但更复杂的操作,比如&#34;改变了这个原子,并且用这个值改变了这个其他数据并执行了这个操作,并且这些操作相互依赖,而不是必须通过互斥锁来保护它。最好的方法是使用互斥锁,原子操作来命名,并将其放入如下所述的方法中。

一个课程可以帮助你将d及其互斥锁设为私有,并且只能由读者和设置者进行更改和读取,这些读者和设置者正在为您执行互斥锁处理。即封装的概念。 std::atomic在没有锁定的平台上完成了这一点。

但是你的循环会非常慢,所以std::atomic仍然是最好的。

简短:两种情况都是错误的(关于良好做法)

你的课程大致应该是这样的

#include<mutex>
#include<atomic>

class MyClass {
public:
    std::atomic<int> i;
    MyClass() = default; //you could also just spare this line because you don't declare other constructors
    double d() {
        std::lock_guard<std::mutex> d_guard(dmutex);
        return this->d_;//this-> is not needed
    }
    void setd(double d) {
        std::lock_guard<std::mutex> d_guard(dmutex);
        d_ = d;
    }
    void add_to_d(double to_add){
        std::lock_guard<std::mutex> d_guard(dmutex);
        d_ += to_add;
    }
private:
    double d_;
    std::mutex dmutex;
};


void ThreadFunction (MyClass &myclass) {
    for (int i = 0; i < 100; i++) {
        myclass.i++;
        myclass.add_to_d(0.5);
    }
}   

答案 1 :(得分:0)

您可能不应该使用包含多个std:atomic<T>变量的类,因为它不能保证它们的一致性:

假设您有类似的课程:

class A{
    std::atomic<int> a1, a2, sum;
public:
    void update(int a1, int a2){
        this->a1 = a1;
        this->a2 = a2;
        this->sum = a1 + a2;
    }
};

void update中可能存在竞争条件:一个线程已更改a1a2并且已停止,第二个线程执行相同操作并且总和,第一个线程唤醒并重新编译总和旧的价值。

因此,只为复杂结构提供一致性的方法是使用mutex