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