多个线程无法无错误地访问同一指针

时间:2014-12-17 12:41:49

标签: c++ multithreading access-violation glfw

我正在使用GLFW3(窗口库)制作应用程序,我的操作系统是Windows 8.1。

我的错误:我在主线程中创建了一个指针,当窗口的线程尝试使用它时,它会获得access violation

在我的应用程序中,我试图创建一个输入处理程序类,它从窗口接收事件并将它们发送到订阅该事件的所有对象。

为此,我有所有想要监听的对象继承InputListener

class InputListener{
public:
    virtual void onKeyDown(int key) = 0;
};

要订阅一个事件,一个对象必须使用一个伪全局(传递给构造类的引用)包装变量,它包含我的InputHandler

// My global wrapper
#include "InputHandler.h"
class Centrum{
public:
    InputHandler inputHandler;
public:
    Centrum(){}
};

InputHandler

class InputHandler{
    private:
        unsigned numEvents;
        InputListener* key_down; // Only trying to test on one subscriber for now.
    public:
        InputHandler();
        void registerKeyDown(InputListener* listener, int key);
        void key_event(int key, int action); // Is indirectly called by glfw window (same thread though)
};

// Implementation
InputHandler::InputHandler(){
    numEvents = 0;
}

void InputHandler::registerKeyDown(InputListener* listener, int key){
    // This is called from my main thread
    key_down = listener;
    key_down->onKeyDown(key); // Properly calls function on my Camera class which inherits InputListener
    numEvents++;
    printf("yes %u\n", numEvents);

}

void InputHandler::key_event(int key, int action){
    // This is called by the window's thread (glfw automatically makes this thread)
    printf("failure %u\n", numEvents); // Properly prints out numEvents
    key_down->onKeyDown(key);         // Runtime error here, access violation
}

订阅输入的示例:

Camera::Camera(Centrum& g_centrum){
    this->g_centrum = g_centrum;
    [...]
    g_centrum.inputHandler.registerKeyDown(this, GLFW_KEY_W);

}

3 个答案:

答案 0 :(得分:1)

指向的变量在可以使用之前就已经死了。因此,当线程尝试使用它时,它会引发运行时错误。

答案 1 :(得分:0)

在这一行中你正在复制Centrum:

this->g_centrum = g_centrum;

然后注册该副本(首次调用onKeyDown,这自然起作用)。但是你还没有注册到原来的Centrum,所以它没有key_down来调用,所以当它试图这样做时,不检查指针是否有效,它就会失败。

我将g_centrum作为指针,并且可能使用指针而不是始终引用Centrum。

答案 2 :(得分:0)

线程具有单独的堆栈,因此只有堆分配的对象才能被多个线程访问。 此外,您应该通过互斥锁防止对这些对象(或至少是并发数据)的并发访问。

如果在Windows线程中实现了Camera,您将创建一个centrum副本。

Camera::Camera(Centrum& g_centrum){
    this->g_centrum = g_centrum;
    [...]
    g_centrum.inputHandler.registerKeyDown(this, GLFW_KEY_W);

}

您应该像Centrum那样实现Centrum *mycentrum = new Centrum(),并将其作为指向相机的指针传递。