2012-03-09 43 views
9

我有一个类表示一个有限状态机,它应该在永久循环中运行并检查它是当前状态。在每个状态机器将设置它的下一个状态并且落入idle状态或做一些工作。我想让另一个线程在工作时改变机器的状态。这将导致竞赛状况如预期。因此,我添加了机器的互斥锁定/解锁打包循环以及允许其他线程更改机器当前状态的公共方法。在C++中处理互斥11

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(); 
    } 
} 

且移动方法,它允许其他线程来改变目前的状态:

void Robot::move() 
{ 
    mutal_state.lock(); 
    previousState = currentState; // Booommm 
    currentState = nextState; 
    mutal_state.unlock(); 
} 

我不能设法找到我做错了!程序崩溃在move()函数的第一行。在另一方面,GDB不与C++ 11的工作和跟踪代码是不可能的......

UPDATE:

周围打码,我可以看到,问题是在移动功能。当程序试图锁定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(); 
} 

程序同时运行。

+0

那么你有没有尝试用打印语句调试? – FrustratedWithFormsDesigner 2012-03-09 19:49:37

+0

@ FrustratedWithFormsDesigner:是的。我知道“爆炸”只发生在某个线程试图调用“move”时。 – 2012-03-09 19:53:14

+0

你使用什么编译器的版本? – ildjarn 2012-03-09 19:53:57

回答

2

我的建议:

1)如果你没有调试器,你怎么能这么肯定它是此举崩溃的第一线?除非您有确凿证据支持,否则始终会质疑您对代码所做的任何假设。

2)我会看看状态s3中的任何有趣的代码,因为这是第一次调用移动将执行的内容。到目前为止,s3中的代码还没有运行。要么这样做,要么删除发布示例中的所有代码栏,以排除此问题。 3)编译器可以在寄存器中创建变量的副本,你应该声明所有的状态为volatile,所以它不知道如何优化。

2

我不能帮你为什么你的代码“爆炸”,但我可以假设问题不在你发布的代码中,因为它对我来说运行良好。

对我来说这将输出:

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(); 

} 

(注:有-D_GLIBCXX_USE_NANOSLEEP编译假设你正在使用gcc,看this问题。)

请注意,上面的代码(也可能是您的代码)对于问题仍然是不幸的,如果在循环再次触发之前调用了两次或更多次,则状态可能会失效。
就像已经提到的意见之一,喜欢lock_guards使用:

std::lock_guard<std::mutex> lock(mutal_state); 
+0

尝试'std :: lock_guard'没有帮助。但是我无法运行你的代码。它终止:抛出'std :: system_error'实例后终止' 什么():操作不允许'' – 2012-03-10 05:19:51

+0

@ sorush -r您必须添加-pthread编译器选项。这将解决这个错误。 – inf 2012-03-10 08:17:28

+0

我已经添加了'-pthread'和'-lpthread'选项。 – 2012-03-10 12:46:36

1

如果你在Linux上使用G ++,你需要为了与-lpthread链接互斥锁或线程的东西才能正常工作。如果你不这样做,它将不会失败链接,但会表现得很糟糕或在运行时崩溃...

+0

使用-pthread选项可能会更好。看到这里:http://stackoverflow.com/q/2127797/893693。不过,我认为他无论如何都这样做了。 – inf 2012-03-10 00:07:59

+0

我使用'-pthread'和'-lpthread'链接器选项。链接没有问题。 – 2012-03-10 05:12:08

1

我在回答我自己的问题!因为我发现这个问题,并且它与C++ 0x的锁定和互斥体实现无关。有一个ImageProcess类应控制Robot的状态。它有一个指向它的父类型Robot*并使用它,将其move其父。为此,我实现了一个workhorse和一个start er函数。该start产生一个std::tread和运行workhorse

void ImageProcess::start() 
{ 
    std::thread x(&ImageProcess::workhorse, *this); 
    x.detach(); 
} 

我意识到this->parent在主力是悬空指针。显然呼叫parent->move()应该会崩溃。但它不会立即崩溃!令人惊讶的是,程序控制进入move()函数,然后尝试更改这个不存在的Robot事物。 (或锁定不存在的互斥信号Robot)。

我发现当调用像std::thread x(&ImageProcess::workhorse, *this); x.join() or x.detach()这样的线程时,代码不再在调用者对象中运行。在Robot::run()ImageProcess::workhorse中测试我打印的地址this&image。有不同的。我还添加了公共布尔fooImageProcessRobot改变了它的价值true,再印它workhorserun,在workhorse值始终0Robot1

我相信这是很奇怪的行为。我不知道这是否是相关的内存模型或ImageProcess所有权不知何故被std::thread x(&ImageProcess::workhorse, *this)后改变...

我做ImageProcess工厂模式类(一切都是静态的!)。现在可以了。