C++ 在C+中处理互斥+;11
我有一个表示有限状态机的类,它应该在一个永久循环中运行并检查它的当前状态。在每个状态中,机器将设置它的下一个状态,并进入C++ 在C+中处理互斥+;11,c++,multithreading,c++11,mutual-exclusion,C++,Multithreading,C++11,Mutual Exclusion,我有一个表示有限状态机的类,它应该在一个永久循环中运行并检查它的当前状态。在每个状态中,机器将设置它的下一个状态,并进入idle状态或执行一些工作。我想让另一个线程在机器工作时改变它的状态。这将导致预期的竞争条件。所以我添加了机器的互斥锁/解锁包装循环和公共方法,允许其他线程更改机器的当前状态 class Robot { public: enum StateType {s1,s2,s3,idle,finish}; void run(); void move(); priv
idle
状态或执行一些工作。我想让另一个线程在机器工作时改变它的状态。这将导致预期的竞争条件。所以我添加了机器的互斥锁/解锁包装循环和公共方法,允许其他线程更改机器的当前状态
class Robot
{
public:
enum StateType {s1,s2,s3,idle,finish};
void run();
void move();
private:
StateType currentState;
StateType nextState;
StateType previousState;
std::mutex mutal_state;
};
实施:
void Robot::run()
{
this->currentState = s1;
while(true)
{
mutal_state.lock();
switch(currentState)
{
case s1:
// do some useful stuff here...
currentState = idle;
nextState = s3;
break;
case s2:
// do some other useful stuff here...
currentState = idle;
nextState = finish;
break;
case s3:
// again, do some useful things...
currentState = idle;
nextState = s2;
break;
case idle:
// busy waiting...
std::cout << "I'm waiting" << std::endl;
break;
case finish:
std::cout << "Bye" << std::endl;
mutal_state.unlock();
return;
}
mutal_state.unlock();
}
}
我找不到我做错了什么!程序在move()
函数的第一行崩溃。另一方面,GDB不能与C++11一起工作,并且无法跟踪代码
更新:
通过对代码的处理,我可以看出问题出在move函数中。当程序试图将代码段锁定在move()
中时,崩溃。例如,如果移动是这样的:
void Robot::move()
{
std::cout << "MOVE IS CALLED" << std::endl;
mutal_state.lock();
//previousState = currentState;
//std::cout << "MOVING" << std::endl;
//currentState = nextState;
mutal_state.unlock();
}
但是当move
是一个简单的函数,不执行任何操作时:
void Robot::move()
{
std::cout << "MOVE IS CALLED" << std::endl;
//mutal_state.lock();
//previousState = currentState;
//std::cout << "MOVING" << std::endl;
//currentState = nextState;
//mutal_state.unlock();
}
void Robot::move()
{
std::cout我的建议:
1) 如果你没有调试器,你怎么能如此确定是第一行代码崩溃了?除非你有确凿的证据支持,否则你总是会质疑你对代码所做的任何假设
2) 我会看看s3状态中的任何有趣的代码,因为这是第一个调用move将执行的。到那时为止,s3中的代码还没有运行。要么这样做,要么删除发布示例中的所有代码栏,以排除这种情况
3) 编译器可能会复制寄存器中的变量,您应该将所有状态声明为volatile,这样它就知道不能以这种方式进行优化。我无法帮助您解释代码“爆炸”的原因,但是我可以假设问题不在您发布的代码中,因为它对我来说运行良好
这将为我输出:
I'm working
...
Bye
代码:
(注意:您必须使用-D_GLIBCXX_USE_NANOSLEEP
编译,假设您使用的是gcc,请参见问题。)
请注意,上面的代码(可能也包括您的代码)仍然可以解决此问题,如果在循环再次触发之前调用了两次或更多次move
,则状态可能会失效。
就像前面提到的一条评论一样,我更喜欢使用锁保护:
std::lock_guard<std::mutex> lock(mutal_state);
std::锁定保护锁定(多状态);
如果你在linux上使用g++,你需要与-lpthread链接,以使互斥锁或线程功能正常工作。如果你不这样做,它不会链接失败,而是会在运行时表现不好或崩溃…我回答我自己的问题!因为我发现了这个问题,它与C的锁定或互斥锁实现无关++0x.有一个ImageProcess
类,它应该控制Robot
的状态。它有一个指向它的父类型Robot*
的指针,并使用它,将移动它的父对象。为此,我实现了一个workhorse
和一个start
er函数。start
生成一个std::tread>代码>并在其上运行workhorse
:
void ImageProcess::start()
{
std::thread x(&ImageProcess::workhorse, *this);
x.detach();
}
我意识到workhorse中的this->parent
是一个悬空的指针。显然调用parent->move()
应该会崩溃。但它不会立即崩溃!令人惊讶的是,程序控制进入move()
函数,然后尝试更改一个不存在的Robot
对象的以前的状态。(或锁定不存在的Robot
的互斥锁)
我发现当调用像std::thread x(&ImageProcess::workhorse,*this);x.join()或x.detach()
这样的线程时,代码不再在调用方对象中运行。为了测试this
和&image
在Robot::run()中的打印地址
和ImageProcess::workhorse
。两者不同。我还向ImageProcess
添加了一个公共布尔值foo
,并在Robot
中将其值更改为true
,然后在workhorse
和run
中打印,在workhorse
中,值始终是0
,但在R中obot
是1
我相信这是非常奇怪的行为。我不知道这是否与内存模型有关,或者在std::thread x(&ImageProcess::workhorse,*this)
之后,ImageProcess
的所有权发生了某种变化
我将ImageProcess
制作成一个工厂模式类(一切都是静态的!)。现在一切正常了。你试过用打印语句调试吗?@fructedWithFormsDesigner:是的。我知道“爆炸”只有当某些线程试图调用move
时才会发生这种情况。您使用的是什么版本的编译器?@ildjarn:我使用的是gcc版本4.6.1(Ubuntu/Linaro 4.6.1-9ubuntu3),线程模型是posix。您最好开始使用锁防护(例如std::lock\u guard
,std::unique\u lock
)而不是手动锁定和解锁。这可能对您当前的问题没有帮助,但只能帮助维护/静态验证。更不用说异常安全了。使用-pthread选项可能更好。请参见此处:。但是,我认为他还是这样做了。我同时使用了-pthread
和-lphread
链接器选项离子。链接没有问题。尝试std::lock\u guard
没有帮助。但是我无法运行您的代码。它终止:terminate在抛出“std::system\u error”的实例后调用what():操作不允许'
@sorush-r您必须添加-pthread编译器选项。这将修复该错误。@sorush-r对我来说没有意义,因为这正是我在没有-pthread
的情况下遇到的错误,我是这样编译的g++-std=c++0x-pthread-D\u GLIBCXX\u使用\u NANOSLEEP-o main.cpp
Oops!对不起,我使用的是Qt-buil将-lpthread
添加到.pro文件后,忘记执行qmake
。感谢您的回答:)
int main() {
Robot r;
auto async_moves = [&] () { // simulate some delayed interaction
std::this_thread::sleep_for(std::chrono::seconds(2)); //See note
for(auto i = 0; i != 3; ++i)
r.move();
};
auto handle = std::async(std::launch::async, async_moves);
r.run();
}
std::lock_guard<std::mutex> lock(mutal_state);
void ImageProcess::start()
{
std::thread x(&ImageProcess::workhorse, *this);
x.detach();
}