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_GAINED
,SDL_TEXTEDITING
和SDL_WINDOWEVENT_SHOWN
之外的任何事件。 所有这些都是在一开始就收到的。我试图找到有关SDL事件处理的教程,因为这是我对问题根源的最佳猜测。 我发现只有基本的事件处理才能观察
SDL_QUIT
,基本的鼠标和键盘事件,以及一个似乎没有帮助的SDL_WINDOWEVENT
。 我没有深入了解事件的意义和处理它们的最佳实践。 这可能无关紧要,因为这可能不是问题的根源。 据我所知,SDL正在投入,因为还有其他线程正在运行。任何人都可以看到我的代码挂起的任何原因,并提供如何解决它的解释?
我的程序结构的快速解释是为了涵盖我省略的代码。
Captor
类启动并运行一个线程来获取屏幕截图以传递给Encoder
。Encoder
启动可变数量的线程,从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
, andSDL_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 onSDL_WINDOWEVENT
s 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 theEncoder
. TheEncoder
starts a variable number of threads that receive a screenshot from theCaptor
, encode the screenshot, then passes the encoding to theScreen
. The passing mechanism is theSynchronousQueue<T>
class that provides paired methodsput(const T&)
andT 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
最满意答案
我想你可以使用它从你的相对路径获得一个绝对路径:
ServletContext ctx = ....; String absolutePath = ctx.getRealPath("/WEB-INF/" + relativePath);
Figured it out...
WTP uses the variable "${catalina.home}", not "${CATALINA_HOME}"...
相关问答
更多-
清理:清除所有webapps并重新部署它们(在Tomcat实例运行时不要这样做) 清理工作目录:清除Tomcat的工作目录,例如编译的JSP所在的位置。 看到这里 。 Clean: Purges all webapps and redeploys them (don't do this while the Tomcat instance is running) Clean working dir: Cleans out Tomcat's work dir, e.g. where compiled JSPs ...
-
使用eclipse wtp将web项目发布到tomcat之后缺少类(missing classes after publish web project into tomcat using eclipse wtp)[2022-12-27]
这发生在我身上很多。 我不会称之为巫毒。 我认为当你在后台更改东西时Eclipse WTP不能很好地工作(例如Maven构建)。 我做什么来解决这个问题是为了避免完全使用它。 相反,我使用Maven WAR插件来部署应用程序: mvn war:inplace tomcat:inplace -DskipTests=true 这个工作非常快,因为它不需要组装和打包战争。 然后取消部署应用程序: mvn tomcat:undeploy 我有脚本 部署并启动托马斯 取消部署并停止tomcat 它看起来像这样: ... -
如果您已经创建了服务器,可以编辑它复制的server.xml模板。 如果您使用项目资源管理器,它位于其他项目 - >服务器 - > Tomcat服务器名称 - > server.xml下 If you've already created the server, you can edit the server.xml template it copies. If you use the project explorer, It is under Other Projects->Servers->Tomcat ...
-
@格雷格, 要考虑的一个选择是让Maven而不是Eclipse WTP将WAR推送到服务器。 这可能需要权衡取决于Eclipse在幕后为您做什么。 然后,您的桌面将更准确地反映CI构建中发生的情况。 无论如何, 本指南深入解释了如何配置tomcat7:deploy目标。 这是一个建议的pom.xml片段,可以帮助您入门:
org.apache.tomcat.maven ... -
现在你必须添加单独的自动测试下载来执行此操作,并且仅在3.1分支中,但它通过Ctrl + Shift + 9启用“显示翻译”命令。 请注意,生成的转换不是服务器在运行时创建的100%相同 - 它不打算执行。 此外,最新的3.0.3版本包含对翻译器的修复,应该清除这些类型的问题(NESTED变量+自动关闭标记)。 3.0.3将于11月到期,并应该干净地更新到Ganymede SR1。 Right now you'd have to add the separate automated tests downlo ...
-
我想你可以使用它从你的相对路径获得一个绝对路径: ServletContext ctx = ....; String absolutePath = ctx.getRealPath("/WEB-INF/" + relativePath); Figured it out... WTP uses the variable "${catalina.home}", not "${CATALINA_HOME}"...
-
据我所知,版本可以位于“功能名称”是“Eclipse Web开发人员工具”的行中 看屏幕截图: As far as I know the version can be located in the row where the "Feature Name" is "Eclipse Web Developer Tools" See screen capture:
-
看起来像anwser在这里: https : //github.com/eclipse/webtools.servertools/blob/master/plugins/org.eclipse.jst.server.tomcat.core/tomcatcore/org/eclipse/jst/server/tomcat /core/internal/TomcatVersionHelper.java 有趣的是,他们不检查外部文件CATALINA_BASE/lib/org/apache/catalina/uti ...
-
您不会将web.xml添加到Tomcat。 你可以在你的jar中部署(放置)包含web-INF下的web.xml的整个战争。 您可以在Tomcat webapps文件夹中放置war文件(通常),也可以在your.tomcat.address / manager下使用其管理器 You don't add web.xml to your Tomcat. You deploy (place) the whole war which includes web.xml under WEB-INF inside you ...
-
在哪里下载Eclipse WTP(Where to download Eclipse WTP)[2022-03-06]
转到帮助 - > Eclipse Market Place 并搜索WTP并安装它。 希望这可以帮助:) Go to Help->Eclipse Market Place and search for WTP and install it. Hope this helps:)