【问题标题】:Solving problems with concurrency c++ windows解决并发 c++ windows 的问题
【发布时间】:2013-11-24 17:44:49
【问题描述】:

我是第一次学习opengl,我正在尝试制作一个简单的程序。我的程序在两个线程中运行,一个线程将程序呈现在屏幕上,而另一个线程更新程序的数据。但是,有时当我尝试关闭我的程序时,我会收到一条令人讨厌的错误消息。我不明白为什么,虽然我觉得这是一个并发错误。这是我的代码。

Main.cpp

#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
#define GLX_GLXEXT_LEGACY

#include <windows.h>
#include "glwindow.h"
#include "example.h"
#include "util.h"

void updateThread(Example* example);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int cmdShow)
{
    const int windowWidth = 1024;
    const int windowHeight = 768;
    const int windowBPP = 16;
    const int windowFullscreen = false;
    GLWindow programWindow(hInstance);
    Example example;
    programWindow.attachExample(&example);

    if (!programWindow.create(windowWidth, windowHeight, windowBPP, windowFullscreen))
    {
        MessageBox(NULL, "Unable to create the OpenGL Window", "An error occurred", MB_ICONERROR | MB_OK);
        programWindow.destroy();
        return 1;
    }

    if (!example.init())
    {
        MessageBox(NULL, "Could not initialize the application", "An error occurred", MB_ICONERROR | MB_OK);
        programWindow.destroy();
        return 1;
    }

    HANDLE thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) updateThread, &example, 0, 0);
    example.setThread(&thread);

    while(programWindow.isRunning())
    {
        programWindow.processEvents();
        example.render();
        programWindow.swapBuffers();
    }

    example.shutdown();
    programWindow.destroy();
    return 0;
}

void updateThread(Example* example)
{
    setFPS(2000);

    while(true)
    {
        example->update();
        sync();
    }
}

Util.cpp

#include "util.h"

int fps;
long timeThen;

void sync()
{
    while(fps == 0);

    long gapTo = 1000 / fps + timeThen;
    long timeNow = time(nullptr);

    while (gapTo > timeNow) 
    {
        timeNow = time(nullptr);
    }

    timeThen = timeNow;
}

void setFPS(int FPS)
{
    fps = FPS;
}

glwindow.cpp

#include <ctime>
#include <iostream>
#include <windows.h>
#include <GL/gl.h>
#include "wglext.h"
#include "glwindow.h"
#include "example.h"

typedef HGLRC (APIENTRYP PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int*);
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;

GLWindow::GLWindow(HINSTANCE hInstance):
    m_isRunning(false),
    m_example(NULL),
    m_hinstance(hInstance),
    m_lastTime(0)
{

}

bool GLWindow::create(int width, int height, int bpp, bool fullscreen)
{
    DWORD dwExStyle;
    DWORD dwStyle;
    m_isFullscreen = fullscreen;
    m_windowRect.left = (long)0;
    m_windowRect.right = (long)width;
    m_windowRect.top = (long)0;
    m_windowRect.bottom = (long)height;
    m_windowClass.cbSize = sizeof(WNDCLASSEX);
    m_windowClass.style = CS_HREDRAW | CS_VREDRAW;
    m_windowClass.lpfnWndProc = GLWindow::StaticWndProc;
    m_windowClass.cbClsExtra = 0;
    m_windowClass.cbWndExtra = 0;
    m_windowClass.hInstance = m_hinstance;
    m_windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    m_windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    m_windowClass.hbrBackground = NULL;
    m_windowClass.lpszMenuName = NULL;
    m_windowClass.lpszClassName = "GLClass";
    m_windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);

    if(!RegisterClassEx(&m_windowClass))
    {
        return false;
    }

    if(m_isFullscreen)                            
    {
        DEVMODE dmScreenSettings;
        memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
        dmScreenSettings.dmSize = sizeof(dmScreenSettings); 
        dmScreenSettings.dmPelsWidth = width;
        dmScreenSettings.dmPelsHeight = height;
        dmScreenSettings.dmBitsPerPel = bpp;
        dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

        if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
        {
            MessageBox(NULL, "Display mode failed", NULL, MB_OK);
            m_isFullscreen = false; 
        }
    }

    if (m_isFullscreen)
    {
        dwExStyle = WS_EX_APPWINDOW;
        dwStyle = WS_POPUP;
        ShowCursor(false);
    }
    else
    {
        dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
        dwStyle = WS_OVERLAPPEDWINDOW;
    }

    AdjustWindowRectEx(&m_windowRect, dwStyle, false, dwExStyle);
    m_hwnd = CreateWindowEx(NULL, "GLClass", "BOGLGP - Chapter 2 - Simple OpenGL Application", dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
        0, 0, m_windowRect.right - m_windowRect.left, m_windowRect.bottom - m_windowRect.top, NULL, NULL, m_hinstance, this);

    if (!m_hwnd)
    {
        MessageBox(NULL, "Window Creation Failed", NULL, MB_OK);
        return 1;
    }

    m_hdc = GetDC(m_hwnd);
    ShowWindow(m_hwnd, SW_SHOW);
    UpdateWindow(m_hwnd);
    m_lastTime = GetTickCount() / 1000.0f;
    return true;
}

void GLWindow::destroy() 
{
    if (m_isFullscreen)
    {
        ChangeDisplaySettings(NULL, 0);
        ShowCursor(true);
    }
}

void GLWindow::attachExample(Example* example)
{
    m_example = example;
}

bool GLWindow::isRunning()
{
    return m_isRunning;
}

void GLWindow::processEvents()
{
    MSG msg;

    while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

void GLWindow::setupPixelFormat(void)
{
    int pixelFormat;

    PIXELFORMATDESCRIPTOR pfd =
    {   
        sizeof(PIXELFORMATDESCRIPTOR),
        1,
        PFD_SUPPORT_OPENGL |
        PFD_DRAW_TO_WINDOW |
        PFD_DOUBLEBUFFER,
        PFD_TYPE_RGBA,
        32,
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        0, 0, 0, 0,
        16,
        0,
        0,
        PFD_MAIN_PLANE,
        0,
        0, 0, 0,
    };

    pixelFormat = ChoosePixelFormat(m_hdc, &pfd);
    SetPixelFormat(m_hdc, pixelFormat, &pfd);
}

LRESULT GLWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_CREATE:
        {
            m_hdc = GetDC(hWnd);
            setupPixelFormat();

            int attribs[] = {
                WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
                WGL_CONTEXT_MINOR_VERSION_ARB, 0,
                0};

            HGLRC tmpContext = wglCreateContext(m_hdc);
            wglMakeCurrent(m_hdc, tmpContext);
            wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress("wglCreateContextAttribsARB");

            if (!wglCreateContextAttribsARB)
            {
                MessageBox(NULL, "Open GL 3.0 Is Not Supported", NULL, MB_OK);
                m_hglrc = tmpContext;
                DestroyWindow(hWnd);
                return 0;
            } 
            else
            {
                m_hglrc = wglCreateContextAttribsARB(m_hdc, 0, attribs);
                wglDeleteContext(tmpContext);
            }

            wglMakeCurrent(m_hdc, m_hglrc);
            m_isRunning = true;
        }

        break;

    case WM_DESTROY:
    case WM_CLOSE:
        wglMakeCurrent(m_hdc, NULL);
        wglDeleteContext(m_hglrc);
        m_isRunning = false;
        PostQuitMessage(0);
        return 0;
        break;

    case WM_SIZE:
        {
            int height = HIWORD(lParam);
            int width = LOWORD(lParam);
            getAttachedExample()->onResize(width, height);
        }

        break;

    case WM_KEYDOWN:
        if (wParam == VK_ESCAPE)
        {
            DestroyWindow(m_hwnd);
        }
        break;

    default:
        break;
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

LRESULT CALLBACK GLWindow::StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    GLWindow* window = NULL;

    if(uMsg == WM_CREATE)
    {
        window = (GLWindow*)((LPCREATESTRUCT)lParam)->lpCreateParams;
        SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG_PTR)window);
    }

    else
    {
        window = (GLWindow*)GetWindowLongPtr(hWnd, GWL_USERDATA);

        if(!window) 
        {
            return DefWindowProc(hWnd, uMsg, wParam, lParam);    
        }
    }

    return window->WndProc(hWnd, uMsg, wParam, lParam);
}

float GLWindow::getElapsedSeconds()
{
    float currentTime = float(GetTickCount()) / 1000.0f;
    float seconds = float(currentTime - m_lastTime);
    m_lastTime = currentTime;
    return seconds;
}

example.cpp

#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "example.h"

Example::Example()
{
    m_rotationAngle = 0.0f;
}

bool Example::init()
{
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    return true;
}

void Example::update()
{
    const float SPEED = 15.0f;
    m_rotationAngle += SPEED;

    if (m_rotationAngle > 360.0f)
    {
        m_rotationAngle -= 360.0f;
    }
}

void Example::render()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glRotatef(m_rotationAngle, 0, 0, 1);
    glBegin(GL_TRIANGLES);
    glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
    glVertex3f(-1.0f, -0.5f, -4.0f);
    glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
    glVertex3f(1.0f, -0.5f, -4.0f);
    glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
    glVertex3f(0.0f,  0.5f, -4.0f);
    glEnd();
}

void Example::shutdown()
{
    TerminateThread(thread, 0);
}

void Example::onResize(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, float(width) / float(height), 1.0f, 100.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

编辑 我确信我的问题在于 example.cpp 和 main.cpp 的线程,但是我包含了所有代码以提供更多上下文。

这是我得到的错误。

【问题讨论】:

  • 您的错误信息是什么?另外,是否可以减少重现问题的代码?这里有很多东西要筛选。
  • OpenGL 上下文基本上是线程不安全的。对该上下文的所有调用必须从同一个线程进行。违反此要求会产生多种故障,包括 AV。

标签: c++ windows multithreading opengl


【解决方案1】:

我看不出您的线程如何干净地退出。 在你的 while 循环中,你应该有类似

while (true) {
  ...
  if (IShouldExit()) break;
}

这可以是简单的东西,比如 bool 或类似的。 然后在你的 main 中,你可以设置标志,然后简单地加入你的线程,让它有时间干净地退出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多