线程池中大量磁盘访问期间出现无响应消息

问题描述

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

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

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

线程池代码是借来的:

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

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

我现在面临的问题是高级磁盘访问阻止了应用刷新窗口界面。 窗口显示臭名昭著的(“无响应”)消息。

我的应用程序包含一个主Frame类和一个Panel类。被调用的函数是“自由函数”。 尝试“强制”更新窗口的代码是:Refresh()和Update()。

已采取的措施:

每200毫秒触发一次事件的wxTimer。

一个带有while循环的单独线程,该线程休眠200ms,并且在线程处理结束时可以通过原子布尔停止。

最后但并非最不重要,但仍然无效

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

秒表计时不一致(从平均200毫秒到370毫秒不等),但足以更新进度条。

必须有一种机制来腾出时间来更新窗口。 我购买了一个可转换文件的应用程序。 有时需要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.dll\n";
        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++\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,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)>,args#0=...,args#1=...,args#2=...) (F:/Data/__C++/wxApps/Mtags/Threadpool.h:62)
#2 0x416ddb ExtractMultiTags(th_cnt=th_cnt@entry=16,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)

解决方法

假设您的期货总能得到解决,那么您可以在刷新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线程,例如在WxThreadHelper中。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...