首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++11中的互斥处理

C++11中的互斥处理
EN

Stack Overflow用户
提问于 2012-03-09 19:47:46
回答 4查看 4.1K关注 0票数 9

我有一个代表有限状态机的类,它应该在一个永久循环中运行,并检查它的当前状态。在每个状态机中,都会设置它的下一个状态,或者进入idle状态,或者做一些工作。我希望允许另一个线程在机器工作时改变其状态。这将像预期的那样导致比赛情况。因此,我添加了机器的互斥锁/解锁包装循环,以及允许其他线程更改机器当前状态的公共方法。

代码语言:javascript
复制
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;
};

执行情况:

代码语言:javascript
复制
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方法:

代码语言:javascript
复制
void Robot::move()
{
    mutal_state.lock();
    previousState = currentState; // Booommm
    currentState = nextState;
    mutal_state.unlock();
}

我找不到我做错了什么!程序在move()函数的第一行崩溃。另一方面,GDB不使用C++11,跟踪代码也不可能.

更新:

在玩代码的时候,我可以看到这个问题在移动函数中。当程序试图锁定move()中的代码块时,就会崩溃。例如,如果移动是这样的:

代码语言:javascript
复制
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();
}

产出如下:

代码语言:javascript
复制
s1
I'm waiting
I'm waiting
MOVE IS CALLED1
The program has unexpectedly finished.

但是,当move是一个简单的函数时,什么都不做:

代码语言:javascript
复制
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();
}

程序同时运行。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-03-09 21:32:13

我的建议:

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

2)我将查看状态s3中任何有趣的代码,因为这是要移动的第一个调用将执行的操作。到目前为止,s3中的代码还没有运行。或者删除张贴的示例中的所有代码条,以排除这一点。

3)编译器可以复制寄存器中的变量,您应该将所有的状态声明为易失性,这样它就不会以这种方式进行优化。

票数 2
EN

Stack Overflow用户

发布于 2012-03-09 21:44:42

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

这将为我输出:

代码语言:javascript
复制
I'm working
...
Bye

代码:

代码语言:javascript
复制
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:

代码语言:javascript
复制
std::lock_guard<std::mutex> lock(mutal_state);
票数 2
EN

Stack Overflow用户

发布于 2012-03-09 22:32:44

如果在linux上使用g++,则需要链接到-lpthread,以便互斥或线程操作正常。如果你不这样做,它不会失败链接,而是会表现不好或崩溃在运行时.

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9640058

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档