如果互斥锁是由成员管理的,那么你需要互斥锁吗?
Do you need mutex for a class/struct if mutex is managed by members?
因此,如果我在线程之间通过引用/指针传递变量,我应该实现互斥或使用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);
}
或
//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();
}
让我们从只访问成员变量(我现在关心的)和成员函数的角度来讨论,假设他们修改这些成员变量并相应地处理互斥。一个比另一个更正确吗?第二个是不必要的吗?
你把事情搞混了:使用stuff作为公共成员不会改变任何东西。你只是在这个指针的差异上采取了额外的方式。
I的本质是:如果两个线程正在更改本身不是原子的数据,那么它们必须通过互斥锁进行同步。两种情况都是关于同步的。
补充:最好在操作中考虑:更改非原子变量是机器代码中的多个操作。std::atomic
的帮助仅仅在于它们提供了通用的操作,这些操作是或似乎是原子的,例如,通过使用特殊的机器指令来比较和改变一个原子机器步骤中的值。但更复杂的操作,比如"改变这个原子,用那个值改变另一个数据,然后做这个",这些操作是相互依赖的,而不是你必须用互斥锁来保护它。最好的方法是把它命名为原子操作,现在用互斥锁命名,并把它放入下面描述的方法中。
一个类可以帮助你把
d
和它的互斥锁设为私有的,并且只由reader和setter来改变和读取它,它们正在为你处理互斥锁。即封装的概念。std::atomic
正是在平台上这样做的,在那里它不是无锁的。
但是你的循环会很慢,所以std::atomic
仍然是最好的。
Short:两种情况都是错误的(关于良好实践)
您的类应该大致如下所示
#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);
}
}
您可能不应该将class与许多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
中可能存在竞争条件:一个线程修改了a1
和a2
并被停止,第二个线程做了同样的事情并求和,第一个线程醒来并用旧值重写sum。
因此,为复杂结构提供一致性的唯一方法是使用mutex
。
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 助记符和指向成员语法的指针
- 用于访问容器<T>数据成员的正确 API
- 内置函数可查看CPP中的成员变量
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 嵌套在类中时无法设置成员数据
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 将函数类成员映射到类本身内部
- 我们可以通过 IPC 传递具有动态管理成员的类对象吗?
- 向量成员在管理类指针C++队列时丢失
- 将指针向量作为类成员进行管理
- 内存管理不良?类成员(布尔值)值大于 1,在递归函数中
- C++内存管理:成员变量是如何存储的
- 当返回对成员变量的引用时,SWIG-Java内存管理
- 如果互斥锁是由成员管理的,那么你需要互斥锁吗?