首页 \ 问答 \ C ++ 11 + SDL2 + Windows:多线程程序在任何输入事件后挂起(C++11 + SDL2 + Windows: Multithreaded program hangs after any input event)

C ++ 11 + SDL2 + Windows:多线程程序在任何输入事件后挂起(C++11 + SDL2 + Windows: Multithreaded program hangs after any input event)

我正在使用C ++ 11,MinGW和Windows API进行屏幕捕获程序。 我正在尝试使用SDL2来观看我的屏幕捕获程序如何实时工作。

窗口打开很好,程序似乎运行良好,只要我只做移动鼠标光标。 但是如果我点击窗口,窗口外的菜单栏或按任意键,SDL窗口会冻结。

我已经为事件设置了一些日志记录来弄清楚发生了什么。 我从未按顺序接收除SDL_WINDOW_FOCUS_GAINEDSDL_TEXTEDITINGSDL_WINDOWEVENT_SHOWN之外的任何事件。 所有这些都是在一开始就收到的。

我试图找到有关SDL事件处理的教程,因为这是我对问题根源的最佳猜测。 我发现只有基本的事件处理才能观察SDL_QUIT ,基本的鼠标和键盘事件,以及一个似乎没有帮助的SDL_WINDOWEVENT 。 我没有深入了解事件的意义和处理它们的最佳实践。 这可能无关紧要,因为这可能不是问题的根源。 据我所知,SDL正在投入,因为还有其他线程正在运行。

任何人都可以看到我的代码挂起的任何原因,并提供如何解决它的解释?

我的程序结构的快速解释是为了涵盖我省略的代码。 Captor类启动并运行一个线程来获取屏幕截图以传递给EncoderEncoder启动可变数量的线程,从Captor接收屏幕截图,对屏幕截图进行编码,然后将编码传递给Screen 。 传递机制是SynchronousQueue<T>类,它提供配对方法put(const T&)T get()以允许生产者和消费者使用资源进行同步; 这些方法超时以允许系统响应以杀死消息。

现在为源文件(希望没有太多的膨胀)。 虽然我很感激有关如何提高应用程序性能的任何意见,但我的重点是使程序具有响应性。

main.cpp中

#include "RTSC.hpp"

int main(int argc, char** argv) {
    RTSC rtsc {
        (uint32_t) stoi(argv[1]),
        (uint32_t) stoi(argv[2]),
        (uint32_t) stoi(argv[3]),
        (uint32_t) stoi(argv[4]),
        (uint32_t) stoi(argv[5]),
        (uint32_t) stoi(argv[6])
    };

    while (rtsc.isRunning()) {
        SwitchToThread();
    }

    return 0;
}

RTSC.hpp

#ifndef RTSC_HPP
#define RTSC_HPP

#include "Captor.hpp"
#include "Encoder.hpp"
#include "Screen.hpp"

#include <iostream>
using namespace std;


class RTSC {
    private:
        Captor *captor;
        Encoder *encoder;

        SynchronousQueue<uint8_t*> imageQueue {1};
        SynchronousQueue<RegionList> regionQueue {1};

        Screen *screen;

    public:
        RTSC(
            uint32_t width,
            uint32_t height,
            uint32_t maxRegionCount,
            uint32_t threadCount,
            uint32_t divisionsAlongThreadWidth,
            uint32_t divisionsAlongThreadHeight
        ) {
            captor = new Captor(width, height, imageQueue);
            encoder = new Encoder(
                width,
                height,
                maxRegionCount,
                threadCount,
                divisionsAlongThreadWidth,
                divisionsAlongThreadHeight,
                imageQueue,
                regionQueue
            );

            screen = new Screen(
                width,
                height,
                width >> 1,
                height >> 1,
                regionQueue
            );

            captor->start();
        }

        ~RTSC() {
            delete screen;
            delete encoder;
            delete captor;
        }

        bool isRunning() const {
            return screen->isRunning();
        }
};

#endif

Screen.hpp

#ifndef SCREEN_HPP
#define SCREEN_HPP

#include <atomic>
#include <SDL.h>
#include <windows.h>

#include "Region.hpp"
#include "SynchronousQueue.hpp"

using namespace std;

class Screen {
    private:
        atomic_bool running {false};
        HANDLE thread;
        SynchronousQueue<RegionList>* inputQueue;
        uint32_t inputHeight;
        uint32_t inputWidth;
        uint32_t screenHeight;
        uint32_t screenWidth;

        SDL_Renderer* renderer;
        SDL_Surface* surface;
        SDL_Texture* texture;
        SDL_Window* window;

        void run() {
            SDL_Event event;
            while (running) {
                while (SDL_PollEvent(&event)) {
                    switch (event.type) {
                        case SDL_QUIT:
                            running = false;
                            break;

                        case SDL_WINDOWEVENT:
                            switch (event.window.event) {
                                case SDL_WINDOWEVENT_CLOSE:
                                    running = false;
                                    break;

                        default:
                            break;
                    }
                }

                try {
                    RegionList rl = inputQueue->get();

                    SDL_RenderClear(renderer);

                    SDL_LockSurface(surface);
                    SDL_FillRect(surface, nullptr, 0);

                    for (uint32_t i = 0; i < rl.count; ++i) {
                        Region &r = rl.regions[i];

                        SDL_Rect rect {
                            (int) r.getX(),
                            (int) r.getY(),
                            (int) r.getWidth(),
                            (int) r.getHeight()
                        };
                        uint32_t color =
                            (r.getRed() << 16) +
                            (r.getGreen() << 8) +
                            r.getBlue();
                        SDL_FillRect(surface, &rect, color);
                    }

                    SDL_UnlockSurface(surface);
                    SDL_UpdateTexture(
                        texture,
                        nullptr,
                        surface->pixels,
                        surface->pitch
                    );
                    SDL_RenderCopyEx(
                        renderer,
                        texture,
                        nullptr,
                        nullptr,
                        0,
                        nullptr,
                        SDL_FLIP_VERTICAL
                    );
                } catch (exception &e) {}

                SDL_RenderPresent(renderer);
                SwitchToThread();
            }
        }

        static DWORD startThread(LPVOID self) {
            ((Screen*) self)->run();
            return (DWORD) 0;
        }

    public:
        Screen(
            uint32_t inputWidth,
            uint32_t inputHeight,
            uint32_t windowWidth,
            uint32_t windowHeight,
            SynchronousQueue<RegionList> &inputQueue
        ): inputQueue {&inputQueue}, inputHeight {inputHeight} {
            SDL_Init(SDL_INIT_VIDEO);

            window = SDL_CreateWindow(
                "RTSC",
                SDL_WINDOWPOS_CENTERED,
                SDL_WINDOWPOS_CENTERED,
                windowWidth,
                windowHeight,
                SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE |
                    SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS
            );

            renderer = SDL_CreateRenderer(window, -1, 0);

            surface = SDL_CreateRGBSurface(
                0,
                inputWidth,
                inputHeight,
                24,
                0xFF << 16,
                0xFF << 8,
                0xFF,
                0
            );

            texture = SDL_CreateTexture(
                renderer,
                surface->format->format,
                SDL_TEXTUREACCESS_STREAMING,
                inputWidth,
                inputHeight
            );

            running = true;
            thread = CreateThread(nullptr, 0, startThread, this, 0, nullptr);
        }

        ~Screen() {
            running = false;
            WaitForSingleObject(thread, INFINITE);
            CloseHandle(thread);

            SDL_FreeSurface(surface);
            SDL_DestroyRenderer(renderer);
            SDL_DestroyWindow(window);
            SDL_Quit();
        }

        bool isRunning() const {
            return running;
        }
};

#endif

I am working on a screen capture program using C++11, MinGW, and the Windows API. I am trying to use SDL2 to watch how my screen capture program works in real time.

The window opens fine, and the program seems to run well so long as I do nothing more than move the mouse cursor. But iff I click in the window, its menu bar, outside the window, or press any keys, the SDL window freezes.

I have set up some logging for the events to figure out what is happening. I never receive any events other than SDL_WINDOW_FOCUS_GAINED, SDL_TEXTEDITING, and SDL_WINDOWEVENT_SHOWN in that order. All of these are received at the start.

I have tried to find tutorials on SDL event handling since that's my best guess as to the source of the problem. I have found nothing more than basic event handling to watch for SDL_QUIT, basic mouse and keyboard events, and one on SDL_WINDOWEVENTs that does not seem to help. I have found nothing in-depth on what the events mean and best practices for handling them. That may not matter, because that might not be the source of the problem. For all I know, SDL is throwing a fit because there are other threads running.

Can anyone see any cause for this hanging in my code and provide an explanation as to how to fix it?

A quick explanation for the structure of my program is in order to cover the code I have omitted. The Captor class starts and runs a thread to grab a screenshot to pass to the Encoder. The Encoder starts a variable number of threads that receive a screenshot from the Captor, encode the screenshot, then passes the encoding to the Screen. The passing mechanism is the SynchronousQueue<T> class that provides paired methods put(const T&) and T get() to allow a producer and a consumer to synchronize using a resource; these methods time out to allow the the system to be responsive to kill messages.

Now for the source files (hopefully without too much bloat). While I would appreciate any comments on how to improve the performance of the application, my focus is on making the program responsive.

main.cpp

#include "RTSC.hpp"

int main(int argc, char** argv) {
    RTSC rtsc {
        (uint32_t) stoi(argv[1]),
        (uint32_t) stoi(argv[2]),
        (uint32_t) stoi(argv[3]),
        (uint32_t) stoi(argv[4]),
        (uint32_t) stoi(argv[5]),
        (uint32_t) stoi(argv[6])
    };

    while (rtsc.isRunning()) {
        SwitchToThread();
    }

    return 0;
}

RTSC.hpp

#ifndef RTSC_HPP
#define RTSC_HPP

#include "Captor.hpp"
#include "Encoder.hpp"
#include "Screen.hpp"

#include <iostream>
using namespace std;


class RTSC {
    private:
        Captor *captor;
        Encoder *encoder;

        SynchronousQueue<uint8_t*> imageQueue {1};
        SynchronousQueue<RegionList> regionQueue {1};

        Screen *screen;

    public:
        RTSC(
            uint32_t width,
            uint32_t height,
            uint32_t maxRegionCount,
            uint32_t threadCount,
            uint32_t divisionsAlongThreadWidth,
            uint32_t divisionsAlongThreadHeight
        ) {
            captor = new Captor(width, height, imageQueue);
            encoder = new Encoder(
                width,
                height,
                maxRegionCount,
                threadCount,
                divisionsAlongThreadWidth,
                divisionsAlongThreadHeight,
                imageQueue,
                regionQueue
            );

            screen = new Screen(
                width,
                height,
                width >> 1,
                height >> 1,
                regionQueue
            );

            captor->start();
        }

        ~RTSC() {
            delete screen;
            delete encoder;
            delete captor;
        }

        bool isRunning() const {
            return screen->isRunning();
        }
};

#endif

Screen.hpp

#ifndef SCREEN_HPP
#define SCREEN_HPP

#include <atomic>
#include <SDL.h>
#include <windows.h>

#include "Region.hpp"
#include "SynchronousQueue.hpp"

using namespace std;

class Screen {
    private:
        atomic_bool running {false};
        HANDLE thread;
        SynchronousQueue<RegionList>* inputQueue;
        uint32_t inputHeight;
        uint32_t inputWidth;
        uint32_t screenHeight;
        uint32_t screenWidth;

        SDL_Renderer* renderer;
        SDL_Surface* surface;
        SDL_Texture* texture;
        SDL_Window* window;

        void run() {
            SDL_Event event;
            while (running) {
                while (SDL_PollEvent(&event)) {
                    switch (event.type) {
                        case SDL_QUIT:
                            running = false;
                            break;

                        case SDL_WINDOWEVENT:
                            switch (event.window.event) {
                                case SDL_WINDOWEVENT_CLOSE:
                                    running = false;
                                    break;

                        default:
                            break;
                    }
                }

                try {
                    RegionList rl = inputQueue->get();

                    SDL_RenderClear(renderer);

                    SDL_LockSurface(surface);
                    SDL_FillRect(surface, nullptr, 0);

                    for (uint32_t i = 0; i < rl.count; ++i) {
                        Region &r = rl.regions[i];

                        SDL_Rect rect {
                            (int) r.getX(),
                            (int) r.getY(),
                            (int) r.getWidth(),
                            (int) r.getHeight()
                        };
                        uint32_t color =
                            (r.getRed() << 16) +
                            (r.getGreen() << 8) +
                            r.getBlue();
                        SDL_FillRect(surface, &rect, color);
                    }

                    SDL_UnlockSurface(surface);
                    SDL_UpdateTexture(
                        texture,
                        nullptr,
                        surface->pixels,
                        surface->pitch
                    );
                    SDL_RenderCopyEx(
                        renderer,
                        texture,
                        nullptr,
                        nullptr,
                        0,
                        nullptr,
                        SDL_FLIP_VERTICAL
                    );
                } catch (exception &e) {}

                SDL_RenderPresent(renderer);
                SwitchToThread();
            }
        }

        static DWORD startThread(LPVOID self) {
            ((Screen*) self)->run();
            return (DWORD) 0;
        }

    public:
        Screen(
            uint32_t inputWidth,
            uint32_t inputHeight,
            uint32_t windowWidth,
            uint32_t windowHeight,
            SynchronousQueue<RegionList> &inputQueue
        ): inputQueue {&inputQueue}, inputHeight {inputHeight} {
            SDL_Init(SDL_INIT_VIDEO);

            window = SDL_CreateWindow(
                "RTSC",
                SDL_WINDOWPOS_CENTERED,
                SDL_WINDOWPOS_CENTERED,
                windowWidth,
                windowHeight,
                SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE |
                    SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS
            );

            renderer = SDL_CreateRenderer(window, -1, 0);

            surface = SDL_CreateRGBSurface(
                0,
                inputWidth,
                inputHeight,
                24,
                0xFF << 16,
                0xFF << 8,
                0xFF,
                0
            );

            texture = SDL_CreateTexture(
                renderer,
                surface->format->format,
                SDL_TEXTUREACCESS_STREAMING,
                inputWidth,
                inputHeight
            );

            running = true;
            thread = CreateThread(nullptr, 0, startThread, this, 0, nullptr);
        }

        ~Screen() {
            running = false;
            WaitForSingleObject(thread, INFINITE);
            CloseHandle(thread);

            SDL_FreeSurface(surface);
            SDL_DestroyRenderer(renderer);
            SDL_DestroyWindow(window);
            SDL_Quit();
        }

        bool isRunning() const {
            return running;
        }
};

#endif

原文:https://stackoverflow.com/questions/22058447
更新时间:2024-04-25 21:04

最满意答案

我想你可以使用它从你的相对路径获得一个绝对路径:

ServletContext ctx = ....;
String absolutePath = ctx.getRealPath("/WEB-INF/" + relativePath);

Figured it out...

WTP uses the variable "${catalina.home}", not "${CATALINA_HOME}"...

相关问答

更多

相关文章

更多

最新问答

更多
  • 在ios 7中的UITableView部分周围绘制边界线(draw borderline around UITableView section in ios 7)
  • Java中的不可变类(Immutable class in Java)
  • 寻求多次出现的表达式(Seeking for more than one occurrence of an expression)
  • linux只知道文件名,不知道在哪个目录,怎么找到文件所在目录
  • Actionscript:检查字符串是否包含域或子域(Actionscript: check if string contains domain or subdomain)
  • 懒惰地初始化AutoMapper(Lazily initializing AutoMapper)
  • 使用hasclass为多个div与一个按钮问题(using hasclass for multiple divs with one button Problems)
  • Windows Phone 7:检查资源是否存在(Windows Phone 7: Check If Resource Exists)
  • EXCEL VBA 基础教程下载
  • RoR - 邮件中的动态主体(部分)(RoR - Dynamic body (part) in mailer)
  • 无法在Google Script中返回2D数组?(Can not return 2D Array in Google Script?)
  • JAVA环境变量的设置和对path , classpth ,java_home设置作用和目的?
  • mysql 关于分组查询、时间条件查询
  • 如何使用PowerShell匹配运算符(How to use the PowerShell match operator)
  • Effective C ++,第三版:重载const函数(Effective C++, Third edition: Overloading const function)
  • 如何用DELPHI动态建立MYSQL的数据库和表? 请示出源代码。谢谢!
  • 带有简单redis应用程序的Node.js抛出“未处理的错误”(Node.js with simple redis application throwing 'unhandled error')
  • 使用前端框架带来哪些好处,相对于使用jquery
  • Ruby将字符串($ 100.99)转换为float或BigDecimal(Ruby convert string ($100.99) to float or BigDecimal)
  • 高考完可以去做些什么?注意什么?
  • 如何声明放在main之后的类模板?(How do I declare a class template that is placed after the main?)
  • 如何使用XSLT基于兄弟姐妹对元素进行分组(How to group elements based on their siblings using XSLT)
  • 在wordpress中的所有页面的标志(Logo in all pages in wordpress)
  • R:使用rollapply对列组进行求和的问题(R: Problems using rollapply to sum groups of columns)
  • Allauth不会保存其他字段(Allauth will not save additional fields)
  • python中使用sys模块中sys.exit()好像不能退出?
  • 将Int拆分为3个字节并返回C语言(Splitting an Int to 3 bytes and back in C)
  • 在SD / MMC中启用DDR会导致问题吗?(Enabling DDR in SD/MMC causes problems? CMD 11 gives a response but the voltage switch wont complete)
  • sed没有按预期工作,从字符串中间删除特殊字符(sed not working as expected, removing special character from middle of string)
  • 如何将字符串转换为Elixir中的函数(how to convert a string to a function in Elixir)