我有一个代表有限状态机的类,它应该在一个永久循环中运行,并检查它的当前状态。在每个状态机中,都会设置它的下一个状态,或者进入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方法:
void Robot::move()
{
mutal_state.lock();
previousState = currentState; // Booommm
currentState = nextState;
mutal_state.unlock();
}我找不到我做错了什么!程序在move()函数的第一行崩溃。另一方面,GDB不使用C++11,跟踪代码也不可能.
更新:
在玩代码的时候,我可以看到这个问题在移动函数中。当程序试图锁定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();
}产出如下:
s1
I'm waiting
I'm waiting
MOVE IS CALLED1
The program has unexpectedly finished.但是,当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();
}程序同时运行。
发布于 2012-03-09 21:32:13
我的建议:
1)如果你没有调试器,你怎么能这么肯定它是第一行崩溃呢?除非你有确凿的证据来支持,否则你总是会质疑你对代码所做的任何假设。
2)我将查看状态s3中任何有趣的代码,因为这是要移动的第一个调用将执行的操作。到目前为止,s3中的代码还没有运行。或者删除张贴的示例中的所有代码条,以排除这一点。
3)编译器可以复制寄存器中的变量,您应该将所有的状态声明为易失性,这样它就不会以这种方式进行优化。
发布于 2012-03-09 21:44:42
我无法帮助你为什么你的代码“爆炸”,但我可以假设问题不是在你发布的代码,因为它运行对我来说很好。
这将为我输出:
I'm working
...
Bye代码:
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();
} (注:假设您使用的是gcc,则必须使用-D_GLIBCXX_USE_NANOSLEEP进行编译,参见this问题。)
请注意,上面的代码--也许也是您的代码--对于这个问题仍然是低俗的,如果在循环再次触发之前调用两次或更多次move,状态可能会失效。
与前面提到的一个注释一样,更喜欢使用lock_guards:
std::lock_guard<std::mutex> lock(mutal_state);发布于 2012-03-09 22:32:44
如果在linux上使用g++,则需要链接到-lpthread,以便互斥或线程操作正常。如果你不这样做,它不会失败链接,而是会表现不好或崩溃在运行时.
https://stackoverflow.com/questions/9640058
复制相似问题