C++ 作为类成员的互斥体
我试图创建一个简单的订户生产者模式,其中多个订户和一个生产者在不同的线程中运行(原因是为了了解更多关于线程的知识)。然而,我正在努力使互斥体成为生产者类的一员。代码如下:C++ 作为类成员的互斥体,c++,multithreading,mutex,C++,Multithreading,Mutex,我试图创建一个简单的订户生产者模式,其中多个订户和一个生产者在不同的线程中运行(原因是为了了解更多关于线程的知识)。然而,我正在努力使互斥体成为生产者类的一员。代码如下: class Producer { private: vector<Subscriber* > subs; thread th; int counter; mutex mux; public: Producer() : counter(counter), th(&Pr
class Producer {
private:
vector<Subscriber* > subs;
thread th;
int counter;
mutex mux;
public:
Producer() : counter(counter), th(&Producer::run, this) {};
void addSubscriber(Subscriber* s);
void notify();
void incrementCounter();
void run();
void callJoin(){th.join(); }
};
void Producer::run() {
for (int i = 0; i < 10; i++) {
incrementCounter();
this_thread::sleep_for(std::chrono::milliseconds(3000));
}
}
void Producer::addSubscriber(Subscriber* s) {
lock_guard<mutex> lock(mux);
subs.push_back(s);
}
void Producer::notify() {
lock_guard<mutex> lock(mux);
for (auto it = subs.begin(); it != subs.end(); ++it) {
(*it)->setCounterCopy(counter);
}
}
void Producer::incrementCounter() {
counter++;
notify();
}
lock\u guard
的目的是防止生产者在向向量添加订户时同时通知向量中的订户。但是,在Project1.exe:0xC0000005:Access violation reading location 0x00000000中0x59963734(msvcp140d.dll)引发的notify异常的锁保护中引发了此异常。
有人知道此异常的原因吗?如果将互斥设置为全局参数,则可以正常工作。也可以随意评论代码的其他问题。穿线对我来说是全新的 所以这里发生的是一个初始化顺序古怪
类成员是按照它们在类中声明的顺序构造的。在您的例子中,这意味着首先是订户向量,然后是线程,然后是计数器(!),最后是互斥。在构造函数中指定初始值设定项的顺序并不重要
但是!构造线程对象需要启动线程并运行其函数。这最终会导致使用互斥锁,可能是在生产者
构造函数实际初始化互斥锁之前。因此,您最终使用了一个尚未构造的互斥体,以及一个尚未初始化的计数器(这并不是问题的原因)
一般来说,每当有成员初始值设定项提到this
或其他类成员(包括调用成员函数)时,都应该小心。它设置用于访问未初始化对象的场景
在您的情况下,只需将互斥和计数器成员移动到线程成员之前就足够了。我只想将此添加到@Sneftel给出的答案中,以供参考: 根据CPP标准(N4713),突出显示了相关部分: 15.6.2初始化基和成员[class.base.init] 13在非委托构造函数中,初始化按以下顺序进行:
(13.1)-首先,并且仅对于派生类最多的构造函数(6.6.2),虚拟基类在 它们在基类的有向无环图的深度优先的从左到右遍历中出现的顺序, 其中“从左到右”是派生类基类说明符列表中基类的出现顺序。
(13.2)-然后,直接基类按照它们出现在基说明符列表中的声明顺序初始化 (不考虑mem初始值设定者的顺序)。
(13.3)-然后,按照类定义中声明的顺序初始化非静态数据成员 (同样,不考虑mem初始值设定者的顺序)。
(13.4)-最后,执行构造函数主体的复合语句。
[注意:声明顺序是为了确保基和成员子对象按与初始化相反的顺序销毁。-结束说明]
要做的第一件事是使用调试器运行它,并在调用完成后检查调用堆栈。此外,您还应该提供一个,您发布的代码几乎就是一个。
Producer():counter(counter)
在我看来很可疑。我不确定,但这可能是未定义的,因为您使用的是代码>计数器< /C>未初始化,因此超出该错误的任何东西都可能出错:“初始化顺序古怪”:)我只喜欢C++中的术语来命名它的所有。quirks@user463035818的确C++需要一个只需要描述与初始化顺序有关的怪癖。
class Subscriber {
private:
string name;
thread th;
atomic<int> counterCopy = 0;
public:
Subscriber(string name) : name(name), th(&Subscriber::run, this) {};
void run() {
while (true) {
cout << name << ": " << counterCopy << endl;
this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
void callJoin() { th.join(); }
void setCounterCopy(int counterCopy) { this->counterCopy = counterCopy; };
};
int main() {
Producer p;
Subscriber s1("Sub1");
p.addSubscriber(&s1);
s1.callJoin();
p.callJoin();
return 0;
}