SDL2访问冲突多个窗口

Posted

技术标签:

【中文标题】SDL2访问冲突多个窗口【英文标题】:SDL2 Access violation multiple windows 【发布时间】:2014-02-24 11:54:30 【问题描述】:

我正在开发 SDL2 应用程序,它需要在多个显示器上具有多个窗口。使用 SDL_ttf 库绘制字符串时出现访问冲突。我还应该提到,应用程序正在单独的线程中打开窗口,并且如果没有使用 SDL_ttf 则可以正常工作。 使用 SDL_ttf 时出现异常:

Unhandled exception at 0x0F2BC191 (SDL2.dll) in SDLMultipleWindows.exe: 0xC0000005: Access violation writing location 0x0100000C.

并且在这个函数中发生了访问冲突:

bool loadFromRenderedText( std::string textureText, SDL_Color textColor )

    SDL_Surface* textSurface = TTF_RenderText_Solid( gFont, textureText.c_str(), textColor );
    SDL_Texture * mTexture = NULL;
    int w, h;
    if( textSurface != NULL )
    
        mTexture = SDL_CreateTextureFromSurface( renderer, textSurface );
        w = textSurface->w;
        h = textSurface->h;
        SDL_FreeSurface( textSurface );
    
    else
    
        printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
    

    SDL_Rect renderQuad =  250, 300, w, h ;
    int result = SDL_RenderCopyEx( renderer, mTexture, NULL, &renderQuad, 0.0, NULL, SDL_FLIP_NONE );
    OutputDebugString(SDL_GetError());
    return true;

异常发生在 SDL_CreateTextureFromSurface(renderer, textSurface);

这是来自 Visual Studio 的堆栈跟踪:

SDL2.dll!SDL_malloc_REAL(unsigned int bytes) Line 4206  C
SDL2.dll!SDL_calloc_REAL(unsigned int n_elements, unsigned int elem_size) Line 4406 C
SDL2.dll!SDL_CreateRGBSurface_REAL(unsigned int flags, int width, int height, int depth, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int Amask) Line 53    C
SDL2.dll!SDL_ConvertSurface_REAL(SDL_Surface * surface, const SDL_PixelFormat * format, unsigned int flags) Line 840    C
SDL2.dll!SDL_CreateTextureFromSurface_REAL(SDL_Renderer * renderer, SDL_Surface * surface) Line 536 C
SDL2.dll!SDL_CreateTextureFromSurface(SDL_Renderer * a, SDL_Surface * b) Line 342   C
SDLMultipleWindows.exe! loadFromRenderedText(std::basic_string<char,std::char_traits<char>,std::allocator<char> > textureText, SDL_Color textColor) Line 162    C++

是我做错了什么还是 SDL_ttf 或 SDL2 不能在多个线程上工作?

在 SDL2 中还有另一种绘制字符串的方法吗?

谢谢!

编辑:

添加部分现有代码:

ClientWindows::ClientWindows(void)

    SDL_Init(SDL_INIT_EVERYTHING);
    IMG_Init(IMG_INIT_PNG);
    TTF_Init();

胎面功能: void ClientWindows::WindowThread(int i) AppWindow* rWindow = new AppWindow(i * 1024, 0); Windows.push_back(rWindow); rWindow->InitScreen();

启动图形功能:

void ClientWindows::StartGraphics(int number)

    for(int i= 0; i<number; i++)
    
        std::thread* wTread = new std::thread(&ClientWindows::WindowThread,this , i);
        Threads.push_back(wTread);
    
.
.
.

客户端窗口构造器:

AppWindow::AppWindow(int x, int y)

    quit = false;
    SCREEN_WIDTH = 1024;
    SCREEN_HEIGHT = 768;
    imagePositionX = 50;
    imagePositionY = 50;
    speed_x = 10;
    speed_y = 10;
    moveX = 10;
    moveY = 10;
    std::ostringstream convert;
    convert << "Graphics";
    convert << x;
    string name = convert.str();

    window = SDL_CreateWindow(name.c_str(), x,
    y, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_OPENGL);
    if (window == nullptr)
        std::cout << SDL_GetError() << std::endl;
    
    opengl3_context = SDL_GL_CreateContext(window);
    SDL_assert(opengl3_context);
    mt.lock();
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (renderer == nullptr)
        std::cout << SDL_GetError() << std::endl;
    
    mt.unlock();
    background = nullptr,image = nullptr;
    background = SDLLoadImage("../res/Image1024x768.png");
    image = SDLLoadImage("../res/Image1024Classic.png");
    animeImage = SDLLoadImage("../res/32_80x80.png");
    gFont = TTF_OpenFont("../res/sample.ttf", 28);

客户端窗口启动图形功能:

void AppWindow::InitScreen(void)

    Clear();
    Render();
    Present();

    //Init fps
    countedFrames = 0;
    fpsTimer.start();

    //For tracking if we want to quit
    Uint32 frameRate = 0;
    while (!quit)
    
        if (fpsTimer.getTicks() > frameRate + 15)
        
            frameRate = fpsTimer.getTicks();
            Clear();
            Render();
            Present();
        
        SDL_Delay(5);
    

有问题的功能:

bool AppWindow::loadFromRenderedText(std::string textureText, SDL_Color textColor)

    SDL_Surface* textSurface = TTF_RenderText_Solid( gFont, textureText.c_str(), textColor );
    SDL_Texture * mTexture = NULL;
    int w, h;
    if( textSurface != NULL )
    
        mTexture = SDL_CreateTextureFromSurface( renderer, textSurface );
        w = textSurface->w;
        h = textSurface->h;
        SDL_FreeSurface( textSurface );
    
    else
    
        printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
    

    SDL_Rect renderQuad =  250, 300, w, h ;
    int result = SDL_RenderCopyEx( renderer, mTexture, NULL, &renderQuad, 0.0, NULL, SDL_FLIP_NONE );
    OutputDebugString(SDL_GetError());
    return true;

【问题讨论】:

【参考方案1】:

除了创建渲染上下文的线程之外,您不能使用来自其他线程的 SDL2 函数,SDL2 保证绘图函数不具有线程安全性。

如果我没记错的话,SDL2 的唯一线程安全部分是将自定义事件推送到事件队列。

所以我猜测 AccessViolation 的发生是因为您尝试使用来自另一个线程的渲染上下文,而不是来自创建它的线程。

【讨论】:

好的,但是我正在每个线程中创建渲染器和窗口的新实例。这不是让它成为那个线程的一部分吗? 您是否在与创建渲染器的线程相同的线程中执行 CreateSurfaceFromTexture? 是的。我创建了 10 个线程,并在每个线程中初始化了新的渲染器和窗口。每个渲染器都有自己的内存地址,但它们之间可能共享一些静态内存。 我知道您在不同的线程中创建它们,我在问您在渲染器上执行操作的线程是否与创建该渲染器的线程相同。 抱歉不清楚,我把这个函数移到了我传递给线程的类中,并且这个类只能从那个线程访问。

以上是关于SDL2访问冲突多个窗口的主要内容,如果未能解决你的问题,请参考以下文章

SDL2 打造显示矩阵 (一)

使用 SDL2_mixer 效果时访问冲突?

CakePHP多个会话

Laravel 7 迁移:语法错误或访问冲突:1068 定义了多个主键

C ++ SDL2:如何将矩形渲染到多个视口中

Laravel 5.8:总是给出多个主键语法或访问冲突错误