C++/GLFW - 使用互斥对象的正确方法?

发布于 2024-07-24 17:01:34 字数 3197 浏览 5 评论 0原文

我正在研究广泛使用多线程的模拟。 问题是,到目前为止我从未使用过任何互斥对象来保护我的数据。 结果是,我遇到了一堆分段错误。

我试图用互斥体锁定/解锁,而:读/写,但这会导致我另一个段错误:

#0 77D27DD2 ntdll!RtlEnumerateGenericTableLikeADirectory() (C:\Windows\system32\ntdll.dll:??)
#1 00000000 ??() (??:??)

当然,我创建了一个测试项目,在其中应用了锁定/解锁基本情况并且它有效,这是一个基本示例,展示了如何使用 GLFW 处理互斥对象:

#include <GL/glfw.h>
#include <iostream>
#include <vector>

using namespace std;

vector<int> table;
GLFWmutex th_mutex;
void GLFWCALL Thread_1(void* arg) {


    glfwLockMutex(th_mutex);
    table.pop_back();
    glfwUnlockMutex(th_mutex);
}

void GLFWCALL Thread_2(void* arg) {

    glfwLockMutex(th_mutex);
    table.erase(table.begin());
    glfwUnlockMutex(th_mutex);

}

int main()
{

    bool    running = true;
    GLFWthread th_1, th_2;

    glfwInit();

    if( !glfwOpenWindow( 512, 512, 0, 0, 0, 0, 0, 0, GLFW_WINDOW ) )
    {
        glfwTerminate();
        return 0;
    }

    glfwSetWindowTitle("GLFW Application");

    for(int i = 0;i < 10; i++) {
        table.push_back(i);
    }


    th_mutex = glfwCreateMutex();
    th_1 = glfwCreateThread(Thread_1, NULL);
    th_2 = glfwCreateThread(Thread_2, NULL);


    while(running)
    {

        // exit if ESC was pressed or window was closed
        running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam( GLFW_OPENED);
    }

    glfwTerminate();

    return 0;
}

我正在工作的项目更大,我有 5 个线程在其上运行,并且有很多向量、映射、队列是同时访问的。 在代码中的某个地方,我尝试做类似的事情:

void GLFWCALL CreateVehicleThread(void* arg) {

     int index = (*static_cast<PulseStateByEntrance*>(arg)).index;
     double t_initial = (*static_cast<PulseStateByEntrance*>(arg)).initial_time;
     double t_final = (*static_cast<PulseStateByEntrance*>(arg)).final_time;
     int pulse = (*static_cast<PulseStateByEntrance*>(arg)).pulse;
     int nb_entrance = (*static_cast<PulseStateByEntrance*>(arg)).nb_entrance;
     int min_time_creation = static_cast<int>(ceil(3600 / pulse));


     while((glfwGetTime() - (*static_cast<PulseStateByEntrance*>(arg)).initial_time)
     < ((*static_cast<PulseStateByEntrance*>(arg)).final_time - (*static_cast<PulseStateByEntrance*>(arg)).initial_time)) {


           double t_elapsed = glfwGetTime() - t_initial;


           if(t_elapsed > min_time_creation) {

                 **int nb_vehicle_per_cycle = static_cast<int>((t_elapsed * pulse)/3600);
                 glfwLockMutex(th_mutex);
                 VehicleManager::CreateVehicles(nb_vehicle_per_cycle, nb_entrance);
                 glfwUnlockMutex(th_mutex);**
                 t_initial = glfwGetTime();

           }

    }


}

我将 VehicleManager:CreateVehicles() 方法放在锁定/解锁之间的原因是因为在这个方法中有这一行:

VehicleManager::vehicles_.push_back(vehicle);

所以我想保护向量:vehicles_ 。 但是,结果我得到了上面的段错误。 即使:

glfwLockMutex(th_mutex);
VehicleManager::vechicles_.push_back(vehicle);
glfwUnlockMutex(th_mutex);

我也遇到了同样的段错误。

我希望,我已经表达得足够清楚,让您能够理解我问题的本质。 我想,并不是所有人都使用过 GLFW,这就是为什么我给你提供了第一个基本示例,以便你可以了解互斥体如何与这个库一起工作。

谢谢 !

I'm working on a simulation that uses multithreading extensively. The thing is that, until now i've never used any mutex objects to protect my data. And the result, is that i'm getting bunch of segmentation faults..

I'm trying to lock/unlock with mutex while : reading/writing but that causes me another segfault :

#0 77D27DD2 ntdll!RtlEnumerateGenericTableLikeADirectory() (C:\Windows\system32\ntdll.dll:??)
#1 00000000 ??() (??:??)

Of course, I created a test project where I applied the lock/unlock thing for a basic situation and it worked, here is a basic example that shows how to deal with Mutex objects using GLFW :

#include <GL/glfw.h>
#include <iostream>
#include <vector>

using namespace std;

vector<int> table;
GLFWmutex th_mutex;
void GLFWCALL Thread_1(void* arg) {


    glfwLockMutex(th_mutex);
    table.pop_back();
    glfwUnlockMutex(th_mutex);
}

void GLFWCALL Thread_2(void* arg) {

    glfwLockMutex(th_mutex);
    table.erase(table.begin());
    glfwUnlockMutex(th_mutex);

}

int main()
{

    bool    running = true;
    GLFWthread th_1, th_2;

    glfwInit();

    if( !glfwOpenWindow( 512, 512, 0, 0, 0, 0, 0, 0, GLFW_WINDOW ) )
    {
        glfwTerminate();
        return 0;
    }

    glfwSetWindowTitle("GLFW Application");

    for(int i = 0;i < 10; i++) {
        table.push_back(i);
    }


    th_mutex = glfwCreateMutex();
    th_1 = glfwCreateThread(Thread_1, NULL);
    th_2 = glfwCreateThread(Thread_2, NULL);


    while(running)
    {

        // exit if ESC was pressed or window was closed
        running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam( GLFW_OPENED);
    }

    glfwTerminate();

    return 0;
}

The project, i'm working is bigger, i have 5 threads running on it, and a lot of vectors, maps, queues are accessed in the same time. Somewhere in the code, i tried to do something like :

void GLFWCALL CreateVehicleThread(void* arg) {

     int index = (*static_cast<PulseStateByEntrance*>(arg)).index;
     double t_initial = (*static_cast<PulseStateByEntrance*>(arg)).initial_time;
     double t_final = (*static_cast<PulseStateByEntrance*>(arg)).final_time;
     int pulse = (*static_cast<PulseStateByEntrance*>(arg)).pulse;
     int nb_entrance = (*static_cast<PulseStateByEntrance*>(arg)).nb_entrance;
     int min_time_creation = static_cast<int>(ceil(3600 / pulse));


     while((glfwGetTime() - (*static_cast<PulseStateByEntrance*>(arg)).initial_time)
     < ((*static_cast<PulseStateByEntrance*>(arg)).final_time - (*static_cast<PulseStateByEntrance*>(arg)).initial_time)) {


           double t_elapsed = glfwGetTime() - t_initial;


           if(t_elapsed > min_time_creation) {

                 **int nb_vehicle_per_cycle = static_cast<int>((t_elapsed * pulse)/3600);
                 glfwLockMutex(th_mutex);
                 VehicleManager::CreateVehicles(nb_vehicle_per_cycle, nb_entrance);
                 glfwUnlockMutex(th_mutex);**
                 t_initial = glfwGetTime();

           }

    }


}

The reason why, i'm putting my VehicleManager:CreateVehicles() method between lock/unlock is because in this method there is this line :

VehicleManager::vehicles_.push_back(vehicle);

So i wanted to protect the vector : vehicles_. But, as a result i got that segfault above. And even with :

glfwLockMutex(th_mutex);
VehicleManager::vechicles_.push_back(vehicle);
glfwUnlockMutex(th_mutex);

i got the same segfault.

I hope, i've made my self clear enough for you to understand the nature of my problem. I suppose, not all of you have worked with GLFW that's why i gave you the first basic example so you can understand how mutexes work with this library.

Thanks !

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦里°也失望 2024-07-31 17:01:34

您可以包装容器,这将使您的代码更易于理解:

template<typename T>
class MultithreadedVector
{
public:
    void pushback( T data )
    {
        glfwLockMutex(m_mutex);
        m_container.push_back( data );
        glfwUnlockMutex(m_mutex);
    }
//then similar for erase etc
private:
    std::vector<T> m_container;
    GLFWmutex m_mutex;
};

You could wrap your containers which will make your code easier to understand:

template<typename T>
class MultithreadedVector
{
public:
    void pushback( T data )
    {
        glfwLockMutex(m_mutex);
        m_container.push_back( data );
        glfwUnlockMutex(m_mutex);
    }
//then similar for erase etc
private:
    std::vector<T> m_container;
    GLFWmutex m_mutex;
};
感性不性感 2024-07-31 17:01:34

没有足够的信息。 但据猜测,互斥体似乎没有正确创建(看起来像 NULL 引用)。 找到调用 glfwCreateMutex() 的点并确保返回有效值。

与您的问题无关,所以附注:

不要这样做:

glfwLockMutex(th_mutex);
<ACTION>
glfwUnlockMutex(th_mutex);

这是 C 风格,因此不是异常安全的。
您应该设置一个类,以便在构造函数中调用锁定,并在析构函数中调用解锁。 然后就有这个类的锁对象。 因此,锁定和解锁通常作为对象创建销毁的一部分发生,因此在出现异常时,锁定将被正确释放。

主要是 RAII,这里有很多关于该主题的文章。

例子:

class MutexLocker
{
    public:
    MutexLocker(GLFWmutex& mutex)
        :m_mutex(mutex)
    {
        glfwLockMutex(m_mutex);
    }
    ~MutexLocker()
    {
        glfwUnlockMutex(m_mutex);
    }
    private:
        GLFWmutex& m_mutex;
};

void myAction()
{
    MutexLocker   lock(th_mutex);

    // Do stuff here:
}

There is not enough information. But as a guess it looks like mutex was not created correctly (looks like a NULL reference). Find the point where you call glfwCreateMutex() and make sure that a valid value is returned.

Not related to your problem so a side note:

don't do this:

glfwLockMutex(th_mutex);
<ACTION>
glfwUnlockMutex(th_mutex);

This is C style and as a result not exception safe.
You should set up a class so that the lock is called in the constructor and the unlock is called in the destructor. Then have a lock object of this class. Thus the lock and unlock happen normally as part of the object creation derstruction, thus in the presence of exceptions the lock will be correctly released.

The princeiple is RAII and their are a lot of articles on the subject here.

Example:

class MutexLocker
{
    public:
    MutexLocker(GLFWmutex& mutex)
        :m_mutex(mutex)
    {
        glfwLockMutex(m_mutex);
    }
    ~MutexLocker()
    {
        glfwUnlockMutex(m_mutex);
    }
    private:
        GLFWmutex& m_mutex;
};

void myAction()
{
    MutexLocker   lock(th_mutex);

    // Do stuff here:
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文