0

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

我正在尝试在读/写时使用互斥锁锁定/解锁,但这会导致我出现另一个段错误:

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

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

#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,这就是为什么我给你第一个基本示例,以便你了解互斥锁如何与这个库一起工作。

谢谢 !

4

2 回答 2

1

没有足够的信息。但作为一种猜测,它看起来像互斥锁没有正确创建(看起来像一个 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:
}
于 2009-06-15T18:15:10.387 回答
1

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

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;
};
于 2009-06-15T19:28:01.707 回答