线程池中大量磁盘访问期间(无响应)消息 我是一个爱好C++编程和多线程编程的程序员,开始我的第一个线程池尝试。 . 我已经到了校长们正在工作的地步
我试图实现的是从一个音乐文件(FLAC)中提取20个标签。一个会话中可能要扫描7000个文件 每个提取都是在具有16个线程的线程池中执行的单独活动, 最终结果(一个未来)被推送到一个结构向量上,供以后处理 线程池代码借用自: 我在Windows10Pro计算机上使用Code::Blocks 20.3、wxWidgets 3.1.3和MinGW 17.1 我现在面临的问题是,高级别的磁盘访问阻止了应用程序刷新窗口界面。 该窗口显示臭名昭著的(未响应)消息 我的应用程序由一个主框架类和一个面板类组成。被调用的函数是“自由函数”。 用于尝试和“强制”更新窗口的代码是:Refresh()和update() 采取的行动: 每200毫秒触发一次事件的WX定时器 一个单独的线程,带有一个while循环,睡眠时间为200ms,当线程处理结束时,可以使用原子bool停止 最后但并非最不重要,但仍然不有效线程池中大量磁盘访问期间(无响应)消息 我是一个爱好C++编程和多线程编程的程序员,开始我的第一个线程池尝试。 . 我已经到了校长们正在工作的地步,c++,multithreading,user-interface,wxwidgets,C++,Multithreading,User Interface,Wxwidgets,我试图实现的是从一个音乐文件(FLAC)中提取20个标签。一个会话中可能要扫描7000个文件 每个提取都是在具有16个线程的线程池中执行的单独活动, 最终结果(一个未来)被推送到一个结构向量上,供以后处理 线程池代码借用自: 我在Windows10Pro计算机上使用Code::Blocks 20.3、wxWidgets 3.1.3和MinGW 17.1 我现在面临的问题是,高级别的磁盘访问阻止了应用程序刷新窗口界面。 该窗口显示臭名昭著的(未响应)消息 我的应用程序由一个主框架类和一个面板类组
wxStopWatch swt;
for (auto &Fut : Futures)
{
TagsStruct TLf = TagsStruct();
TLf = Fut.get();
vTrackTags.push_back(TLf);
if (swt.Time() > 200)
{
// ToDo: code for updating one progress bar
m_wnd->Refresh(); // m_wnd is a pointer passed from the Panel Class
m_wnd->Update();
swt.Start();
}
}
秒表计时不一致(从平均200ms到370ms不等),但足以更新进度条
必须有一种机制来为窗口更新腾出时间。
我买了一个可以转换文件的应用程序。
它有时需要15分钟的时间来表演,而且它可以让16个进度条保持活动和踢腿。
因此,原则上,应该可以在线程运行时更新进度条
希望有人能帮我解决这个问题
路德
添加了按钮事件中的代码:
void FetchTags::m_btn_Fetch_OnButtonClick( wxCommandEvent& event )
{
// Set Collection Name
wxString wsCollection{m_textCtrl1->GetLineText(0)}, wsCol{"Empty"};
if (wsCollection != "") { wsCol = wsCollection; };
// Set number of threads
int t_cnt = m_spinCtrl1->GetValue();
if (wsTrackFiles.size() > 0)
{
Elements(false);
auto TrackTags = ExtractMultiTags(t_cnt, wsTrackFiles, wsCol, this); // though thread-pool
Elements(true);
if (TrackTags.size() > 0)
{
// Grid is cleared in OnDropFiles()
m_grid1->AppendRows(TrackTags.size());
FillGrid(TrackTags);
WriteToCSV(TrackTags);
}
std::cout << "i_cnt = " << i_cnt << std::endl;
}
}
void FetchTags::m_btn_Fetch_onbutton单击(wxCommandEvent&event)
{
//设置集合名称
wxString wsCollection{m_textcrl1->GetLineText(0)},wsCol{“Empty”};
if(wsCollection!=“”){wsCol=wsCollection;};
//设置线程数
int t_cnt=m_spinCtrl1->GetValue();
如果(wsTrackFiles.size()>0)
{
元素(假);
auto TrackTags=ExtractMultiTags(t_cnt,wsTrackFiles,wsCol,this);//通过线程池
元素(真);
如果(TrackTags.size()>0)
{
//已在OnDropFiles()中清除网格
m_grid1->AppendRows(TrackTags.size());
填充网格(轨迹标记);
WriteToCSV(TrackTags);
}
std::cout Update();
swt.Start();
}
}
//卸载.dll
FreeTagsLibrary();
返回标签;
}
---从曲目文件中提取---
静态标记struct ExtractTrackTags(标记struct标记行、wxString wsFile、wxString wsCollection)
{
//将std::string转换为LPWSTR
LPWSTR wsFileName{ConvertString(wsFile)};
//加载标签
标记库加载(标记,wsFileName,ttAutomatic,TRUE);
如果(已加载标签库(标签,t自动))
{
/*提取音频属性*/
taudios;
if(!TagsLibrary_GetAudioAttributes(标记、TAudioType::atAutomatic和Attribs))
{
TagLine.PlayTime=std::_cxx11::to_字符串(Attribs.PlayTime);
//等等。。。
}
/*提取命名标记*/
//唱片艺术家
std::wstring ws05(TagsLibrary_GetTag(Tags,ConvertString(“相册艺术家”),ttAutomatic));
TagLine.AlbumArtist假设您的未来总是得到解决,您可以在刷新UI直到其准备就绪的同时,在每个未来上旋转一小段时间:
for (auto &Fut : Futures)
{
while (true) {
auto status = Fut.wait_for(100ms);
if (status == std::future_status::ready) break;
m_wnd->Refresh(); // Assuming these functions actually run the event loop
m_wnd->Update();
}
TagsStruct TLf = Fut.get();
vTrackTags.push_back(TLf);
}
或者,您可以保留阻塞循环,但在另一个线程中执行,并在准备就绪时将WxEvent发送回UI线程,例如在中。听起来这可能是一个I/O受限的操作,在这种情况下,更多的线程只会使进程变慢,特别是在“旋转生锈”的硬盘驱动器上(与SSD相反)。你用1个线程试过了吗?如果没有别的,它会使“无响应”问题更容易找到。@Thomas。我用1个线程试过,结果是一样的。用16个线程,它完成处理的时间比1个线程少一半多一点。你在主(UI)上做了大量IO吗线程?不要。保持UI线程空闲并从工作线程更新它。@Botje。主UI线程仅用于与UI相关的命令和事件。按钮事件启动空闲函数以激活线程池和标记提取。您确定没有无意中阻塞UI线程吗?拥有线程池并正确使用线程池We’通常是两种不同的东西,差异可能是微妙而微妙的。我已经测试了您的第一个建议。Fut.Get()仍然会阻塞UI。我将查看您的第二个建议。您是否使用调试器验证它是否卡在Get调用中?窗口显示(未响应)执行7到10秒后返回消息。调试器有何帮助?执行速度将足够慢,以允许窗口更新。对吗?最终结果总是100%正常。当Windows确定您的程序“没有响应”时,调试器将告诉您堆栈顶部有什么函数。我假设更新()调用运行事件循环并处理消息,所以要么该假设为false,要么您在某处有另一个阻塞调用。
static TagsStruct ExtractTrackTags(TagsStruct TagLine, wxString wsFile, wxString wsCollection)
{
// Convert std::string to LPWSTR
LPWSTR wsFileName{ConvertString(wsFile)};
// Load the tags
TagsLibrary_Load(Tags, wsFileName, ttAutomatic, TRUE);
if (TagsLibrary_Loaded(Tags, ttAutomatic))
{
/* Extract the Audio Attributes */
TAudioAttributes Attribs;
if (!TagsLibrary_GetAudioAttributes(Tags, TAudioType::atAutomatic, &Attribs))
{
TagLine.PlayTime = std::__cxx11::to_string(Attribs.PlayTime);
// etc...
}
/* Extract the named TAGs*/
//AlbumArtist
std::wstring ws05(TagsLibrary_GetTag(Tags, ConvertString("ALBUMARTIST"), ttAutomatic));
TagLine.AlbumArtist << std::string(ws05.begin(), ws05.end());
// etc...
}
else
{
TagLine.OK = false;
wxString msg = "\tNo tags found in:\n" + wsFile ;
wxMessageBox(msg, _("ERROR..."));
}
return TagLine;
}
#0 ?? ExtractMultiTags (th_cnt=th_cnt@entry=16, vwsFiles=..., wsCol=..., m_wnd=m_wnd@entry=0x1676f30) (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:167)
#1 0x402e12 FetchTags::m_btn_Fetch_OnButtonClick(this=0x1676f30, event=...) (f:/sdks/mingw-17.1/include/c++/9.2.0/bits/basic_string.h:263)
#2 0x417d68 wxAppConsoleBase::CallEventHandler(wxEvtHandler*, wxEventFunctor&, wxEvent&) const() (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:190)
#3 0x507c91 wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:190)
#4 0x508137 wxEvtHandler::SearchDynamicEventTable(wxEvent&) () (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:190)
#5 0x5084a5 wxEvtHandler::TryHereOnly(wxEvent&) () (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:190)
#6 0x50853b wxEvtHandler::ProcessEventLocally(wxEvent&) () (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:190)
#7 0x508622 wxEvtHandler::ProcessEvent(wxEvent&) () (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:190)
#8 0x50a71c wxEvtHandler::SafelyProcessEvent(wxEvent&) () (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:190)
#9 0x57c373 wxButton::SendClickEvent() () (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:190)
#10 0x56095f wxWindow::HandleCommand(unsigned short, unsigned short, HWND__*) () (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:190)
#11 0x56bcaf wxWindow::MSWHandleMessage(long long*, unsigned int, unsigned long long, long long) () (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:190)
#12 0x55988f wxWindow::MSWWindowProc(unsigned int, unsigned long long, long long) () (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:190)
#13 0x7ffeebf05c7d ?? () (??:??)
#0 ?? std::unique_lock<std::mutex>::unique_lock (__m=..., this=0x162dc80) (f:/sdks/mingw-17.1/include/c++/9.2.0/bits/move.h:47)
#1 ?? Thread_Pool::execute<TagsStruct (*)(TagsStruct, wxString, wxString), TagsStruct&, wxString&, wxString&> (this=this@entry=0x162e6e0, function=function@entry=0x411612 <ExtractTrackTags(TagsStruct, wxString, wxString)>, args#0=..., args#1=..., args#2=...) (F:/Data/__C++/wxApps/Mtags/Threadpool.h:62)
#2 0x416ddb ExtractMultiTags(th_cnt=th_cnt@entry=16, vwsFiles=..., wsCol=..., m_wnd=m_wnd@entry=0x1676f30) (F:\Data\__C++\wxApps\Mtags\TrackTags.cpp:167)
#3 0x402e12 FetchTags::m_btn_Fetch_OnButtonClick(this=0x1676f30, event=...) (f:/sdks/mingw-17.1/include/c++/9.2.0/bits/basic_string.h:263)
for (auto &Fut : Futures)
{
while (true) {
auto status = Fut.wait_for(100ms);
if (status == std::future_status::ready) break;
m_wnd->Refresh(); // Assuming these functions actually run the event loop
m_wnd->Update();
}
TagsStruct TLf = Fut.get();
vTrackTags.push_back(TLf);
}