在线程池中进行大量磁盘访问时出现(未响应)消息



我是一名业余程序员,学习C++和多线程,并开始第一次尝试线程池。。我已经到了校长们正在工作的地步。

我试图实现的是从音乐文件(FLAC(中提取20个标签。一个会话中可能有7000个文件要扫描。

每个提取是在具有16个线程的线程池中执行的单独活动,并且将最终结果(未来(推送到结构的向量以供稍后处理。

线程池代码借用自:

https://codereview.stackexchange.com/questions/221626/c17-thread-pool

我在Windows 10 Pro计算机上使用代码::Blocks 20.3、wxWidgets 3.1.3和MinGW 17.1。

我现在面临的问题是,高级别的磁盘访问使应用程序无法刷新窗口界面。该窗口显示臭名昭著的(未响应(消息。

我的应用程序由一个主Frame类和一个Panel类组成。被调用的函数是";自由函数";。用于尝试和";"力";窗口的更新为:Refresh((和update((。

采取的行动:

wxTimer,每200ms触发一个事件。

一个单独的线程,带有while循环,睡眠200ms,并且可以在线程处理结束时使用原子bool停止。

最后但同样重要的是,仍然无效

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

//--

std::vector<TagsStruct> ExtractMultiTags(int th_cnt, std::vector<wxString> vwsFiles, wxString wsCol, wxWindow *m_wnd)
{
wxStopWatch swf;
// Load the TagsLibrary DLL
if (!InitTagsLibrary())
{
//* Could not load the .dll
wxString msg = "tError while loading TagsLib.dlln";
wxMessageBox(msg, _("ERROR..."));
}
// Clear existing Vector of Futures
vTrackTags.clear();
// Create Thread Pool
Thread_Pool Pool(th_cnt);
std::vector<std::future<TagsStruct>> Futures;
// Do the work
for(auto &aTrack : vwsFiles)
{
TagsStruct TLp = TagsStruct();
Futures.push_back(Pool.execute(ExtractTrackTags, TLp, aTrack, wsCol));
}
// Get the results
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->Update();
swt.Start();
}
}
// Unload the .dll
FreeTagsLibrary();
return vTrackTags;
}

---从轨道文件中提取---

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

以下是上带有断点的调用堆栈

"Futures.push_back(Pool.execute(ExtractTrackTags,TLp,aTrack,wsCol((">

#0 ??   ExtractMultiTags (th_cnt=th_cnt@entry=16, vwsFiles=..., wsCol=..., m_wnd=m_wnd@entry=0x1676f30) (F:Data__C++wxAppsMtagsTrackTags.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++wxAppsMtagsTrackTags.cpp:190)
#3 0x507c91 wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () (F:Data__C++wxAppsMtagsTrackTags.cpp:190)
#4 0x508137 wxEvtHandler::SearchDynamicEventTable(wxEvent&) () (F:Data__C++wxAppsMtagsTrackTags.cpp:190)
#5 0x5084a5 wxEvtHandler::TryHereOnly(wxEvent&) () (F:Data__C++wxAppsMtagsTrackTags.cpp:190)
#6 0x50853b wxEvtHandler::ProcessEventLocally(wxEvent&) () (F:Data__C++wxAppsMtagsTrackTags.cpp:190)
#7 0x508622 wxEvtHandler::ProcessEvent(wxEvent&) () (F:Data__C++wxAppsMtagsTrackTags.cpp:190)
#8 0x50a71c wxEvtHandler::SafelyProcessEvent(wxEvent&) () (F:Data__C++wxAppsMtagsTrackTags.cpp:190)
#9 0x57c373 wxButton::SendClickEvent() () (F:Data__C++wxAppsMtagsTrackTags.cpp:190)
#10 0x56095f    wxWindow::HandleCommand(unsigned short, unsigned short, HWND__*) () (F:Data__C++wxAppsMtagsTrackTags.cpp:190)
#11 0x56bcaf    wxWindow::MSWHandleMessage(long long*, unsigned int, unsigned long long, long long) () (F:Data__C++wxAppsMtagsTrackTags.cpp:190)
#12 0x55988f    wxWindow::MSWWindowProc(unsigned int, unsigned long long, long long) () (F:Data__C++wxAppsMtagsTrackTags.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++wxAppsMtagsTrackTags.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)

假设你的未来总是得到解决,你可以在刷新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);
}

或者,您可以保留阻塞循环,但在另一个线程中执行,并在UI线程准备好时将WxEvent发送回UI线程,例如在WxThreadHelper中。

最新更新