0

我正在开发需要在多个监视器上具有多个窗口的 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);
}

客户端窗口 startGraphics 函数:

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;
}
4

1 回答 1

0

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

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

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

于 2014-02-24T13:02:15.840 回答