Jump to content
Yaron

Responsive UI with heavy background threads running in idle priority

Recommended Posts

I'm the author of Zoom Player a Windows media player/home theater application.

One of Zoom Player's features is that it scrapes information on the video file using multiple mechanism.

 

Two of these mechanisms are somehow severely lagging my user interface even though I'm running the code in separate threads with Idle priority:

1. Running MediaInfo.dll on the media file.

2. Using a non-visual background directshow graph using LAV Filters (directshow filters) to extract a video frame from the video.

 

Other than moving this functionality to completely separate processes, is there a method to ensure my UI (running in the main thread) remains responsive?

Share this post


Link to post

The only way your worker threads could be causing the UI to lag is if they are making the UI thread wait for lengthy periods of time, such as by synchronizing with the UI thread, submitting large amounts of asynchronous notifications to the UI thread, not yielding to the CPU so the UI thread gets starved for CPU time, etc.  But without seeing your actual code, it is hard to say for sure why your UI is lagging.  That is what the debugger is meant for.

Share this post


Link to post

How exactly are you spawning the threads? Afaik, TThread.Create will always use the same logical CPU core as your main application. To make Windows to spread workers on multiple cores you need to use BeginThread... at least this is how it worked back in D7.

Share this post


Link to post
22 minutes ago, aehimself said:

TThread.Create will always use the same logical CPU core as your main application.

Did you really mean logical core? That would completely defeat the purpose of logical cores.

 

Anyhow, TThread.Create calls BeginThread which calls the CreateThread API function. Nothing special there. The system scheduler will in the majority of cases take care of running the thread on the most suitable core.

 

23 minutes ago, aehimself said:

at least this is how it worked back in D7

LOL

 

I doubt it. That would require a call to SetThreadAffinityMask or SetProcessAffinityMask.

  • Like 1

Share this post


Link to post

Sorry, true that; it's physical cores not logical ones. Please disregard my previous comment.

Share this post


Link to post

Here are more details (it's somewhat big, but may help others in the future):

 

1. I have an Idle priority information-scraping thread so the UI won't be affected by the scraping process.
2. The scraping thread pre-creates & uses an idle priority TMediaInfoThread thread (see below).
3. The scraping activates the mediainfo thread.
4. This is the mediainfo's DLL pascal header file : https://github.com/MediaArea/MediaInfoLib/blob/master/Source/MediaInfoDLL/MediaInfoDLL.pas
5. And you can download the DLL here https://mediaarea.net/en/MediaInfo/Download/Windows

 

Code used to activate MediaInfo data gathering thread:

   MediaInfoThread.MediaName  := MediaName;
   MediaInfoThread.ScrapeType := niVideo;
   MediaInfoThread.ResumeThread;

   // do other scraping related meta-data gathering (e.g. online DB lookup) while mediainfo is processing to maximize concurrently/performance.

   While MediaInfoThread.IsSuspended = False do Sleep(1);
   If MediaInfoThread.miResult = True then


The MediaInfo thread code:

Type
  TMediaInfoThread = Class(TThread)
    procedure execute; override;
  private
    FEvent             : THandle;
  public
    ScraperThreadIndex : Integer;
    IsSuspended        : Boolean;
    ScrapeType         : Integer;
    MediaName          : WideString;
    miResult           : Boolean;
    miWidth            : Integer;
    miHeight           : Integer;
    miDuration         : Double;
    miIcons            : WideString;
    miMediaTAGs        : TZPTAGRec;
    Closed             : PBoolean;
    procedure ResumeThread;
  end;


procedure TMediaInfoThread.Execute;
begin
  {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(ScraperThreadIndex)+'.txt','Thread Created, ID #'+IntToStr(ThreadID));{$ENDIF}
  FEvent := CreateEvent(nil,
                        False,    // auto reset
                        False,    // initial state = not signaled
                        nil);

  ResetTagData(miMediaTAGs);                      
  ScrapeType  := niVideo;
  IsSuspended := True;
  {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(ScraperThreadIndex)+'.txt','Thread Initially Suspended');{$ENDIF}
  WaitForSingleObject(FEvent, INFINITE);  // Wait to start processing
  {$IFDEF LOC1ALTRACE}
  DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(ScraperThreadIndex)+'.txt','Thread Initially Resumed'+CRLF);
  {$ENDIF}
  While (Terminated = False) do
  Begin
    {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(ScraperThreadIndex)+'.txt','MediaInfo on "'+MediaName+'" (before)');{$ENDIF}
    miResult := MediaInfo_GetMediaInfoCache(MediaName,ScrapeType,miIcons,miWidth,miHeight,miDuration,@miMediaTAGs,ScraperThreadIndex);
    {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(ScraperThreadIndex)+'.txt','MediaInfo on "'+MediaName+'" (after)');{$ENDIF}
    If Terminated = False then
    Begin
      IsSuspended := True;
      {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(ScraperThreadIndex)+'.txt','MediaInfo complete, Thread Suspended'+CRLF);{$ENDIF}
      WaitForSingleObject(FEvent, INFINITE);  // No more Work
      {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(ScraperThreadIndex)+'.txt','Thread Resumed');{$ENDIF}
      If Terminated = False then ResetTagData(miMediaTAGs);
    End;
  End;
  {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(ScraperThreadIndex)+'.txt','Close event handle');{$ENDIF}
  CloseHandle(fEvent);

  If @Closed <> nil then Closed^ := True;

  {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(ScraperThreadIndex)+'.txt','Thread Terminated');{$ENDIF}
end;


procedure TMediaInfoThread.ResumeThread;
begin
  SetEvent(FEvent);
  IsSuspended := False;
end;

function MediaInfo_GetMediaInfo(FileName : WideString; ScrapeType : Integer; miData : PMediaInfoDataRecord; grabThreadID : Integer) : Boolean;
var
  miHandle       : Cardinal;
  sFormat        : WideString;
  sFormatVersion : WideString;
  sFormatString  : WideString;
  sProfile       : WideString;
  sCodecID       : WideString;
  sScanType      : WideString;
  sDuration      : WideString;
  aCount         : Integer;
  vCount         : Integer;
  I              : Integer;
  mWidth         : Integer;
  mHeight        : Integer;
  mChannels      : Integer;
  iWidth         : Integer;
  iHeight        : Integer;
  iChannels      : Integer;
  iCodec         : Integer;
  S              : String;
begin
  {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','MediaInfo_GetMediaInfo (before)');{$ENDIF}
  Result := False;
  With miData^ do
  Begin
    iconFormat     := niNone;
    iconResolution := niNone;
    iconVideo      := niNone;
    iconAudio      := niNone;
    iconChannels   := niNone;
    ResetTagData(TAGs);

    If MediaInfoLoaded = True then
    Begin
      {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','MediaInfoLoaded = True');{$ENDIF}
      miHandle        := MediaInfo_New;
      {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','MediaInfo Handle : '+IntToHex(miHandle,8));{$ENDIF}
      If MediaInfo_Open(miHandle, PWideChar(FileName)) = 1 then
      Begin
        {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','Open successful');{$ENDIF}
        Result := True;

        // Duration
        sDuration      := MediaInfo_Get(miHandle, Stream_General, 0, 'Duration'      , Info_Text, Info_Name);
        mediaDuration  := StrToFloatDef(sDuration,0) / 1000;
        {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','Duration : '+sDuration);{$ENDIF}

        // File format
        {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','*** File Format ');{$ENDIF}
        sFormat        := MediaInfo_Get(miHandle, Stream_General, 0, 'Format'        , Info_Text, Info_Name);
        {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','Format : '+sFormat);{$ENDIF}
        sFormatVersion := MediaInfo_Get(miHandle, Stream_General, 0, 'Format_Version', Info_Text, Info_Name);
        {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','FormatVersion : '+sFormatVersion);{$ENDIF}
        sProfile       := MediaInfo_Get(miHandle, Stream_General, 0, 'Format_Profile', Info_Text, Info_Name);
        {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','Profile : '+sProfile);{$ENDIF}
        iconFormat     := MediaInfo_FormatToNavIcon(sFormat,sFormatVersion,sProfile);

        If ScrapeType = niVideo then
        Begin
          // Video Codec & Resolution
          {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','*** Video Codec & Resolution');{$ENDIF}
          mWidth  := -1;
          mHeight := -1;
          vCount := MediaInfo_Count_Get(miHandle, Stream_Video, -1);
          {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','Video Streams : '+IntToStr(vCount));{$ENDIF}
          For I := 0 to vCount-1 do
          Begin
            iWidth         := StrToIntDef(MediaInfo_Get(miHandle, Stream_Video, I, 'Width' , Info_Text, Info_Name),-1);
            iHeight        := StrToIntDef(MediaInfo_Get(miHandle, Stream_Video, I, 'Height', Info_Text, Info_Name),-1);

            If (iWidth > mWidth) or (iHeight > mHeight) then
            Begin
              {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt',IntToStr(I)+'. Video Resolution : '+IntToStr(iWidth)+'x'+IntToStr(iHeight));{$ENDIF}
              mWidth         := iWidth;
              mHeight        := iHeight;
              sFormat        := MediaInfo_Get(miHandle, Stream_Video, I, 'Format'        , Info_Text, Info_Name);
              {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt',IntToStr(I)+'. Format : '+sFormat);{$ENDIF}
              sFormatVersion := MediaInfo_Get(miHandle, Stream_Video, I, 'Format_Version', Info_Text, Info_Name);
              {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt',IntToStr(I)+'. FormatVersion : '+sFormatVersion);{$ENDIF}
              sProfile       := MediaInfo_Get(miHandle, Stream_Video, I, 'Format_Profile', Info_Text, Info_Name);
              {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt',IntToStr(I)+'. Profile : '+sProfile);{$ENDIF}
              sScanType      := TNT_WideLowercase(MediaInfo_Get(miHandle, Stream_Video, I, 'ScanType', Info_Text, Info_Name));
              {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt',IntToStr(I)+'. ScanType : '+sScanType);{$ENDIF}
              sCodecID       := MediaInfo_Get(miHandle, Stream_Video, I, 'CodecID'       , Info_Text, Info_Name);
              {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt',IntToStr(I)+'. CodecID : '+sCodecID);{$ENDIF}

              iconResolution := MediaInfo_ResolutionToNavIcon(mWidth,mHeight,sScanType);
              iconVideo      := MediaInfo_VideoCodecToNavIcon(sFormat,sFormatVersion,sCodecID,sProfile);
              mediaWidth     := mWidth;
              mediaHeight    := mHeight;
            End;
          End;
        End
          else
        Begin
          // Audio TAGs
          TAGs.tgTitle     := UTF8Decode(MediaInfo_Get(miHandle, Stream_General, 0, 'Track'              , Info_Text, Info_Name));
          TAGs.tgGenre     := UTF8Decode(MediaInfo_Get(miHandle, Stream_General, 0, 'Genre'              , Info_Text, Info_Name));
          TAGs.tgTrack     := UTF8Decode(MediaInfo_Get(miHandle, Stream_General, 0, 'Track/Position'     , Info_Text, Info_Name));
          TAGs.tgArtist    := UTF8Decode(MediaInfo_Get(miHandle, Stream_General, 0, 'Performer'          , Info_Text, Info_Name));
          TAGs.tgAlbum     := UTF8Decode(MediaInfo_Get(miHandle, Stream_General, 0, 'Album'              , Info_Text, Info_Name));
          TAGs.tgYear      := UTF8Decode(MediaInfo_Get(miHandle, Stream_General, 0, 'Recorded_Date'      , Info_Text, Info_Name));
          TAGs.tgAuthor    := UTF8Decode(MediaInfo_Get(miHandle, Stream_General, 0, 'WrittenBy'          , Info_Text, Info_Name));
          TAGs.tgComment   := UTF8Decode(MediaInfo_Get(miHandle, Stream_General, 0, 'Comment'            , Info_Text, Info_Name));
          TAGs.tgURL       := UTF8Decode(MediaInfo_Get(miHandle, Stream_General, 0, 'Track/Url'          , Info_Text, Info_Name));
          TAGs.tgCopyright := UTF8Decode(MediaInfo_Get(miHandle, Stream_General, 0, 'Copyright'          , Info_Text, Info_Name));
          S                     :=            MediaInfo_Get(miHandle, Stream_General, 0, 'Encoded_Application', Info_Text, Info_Name);
          If S = '' then S      :=            MediaInfo_Get(miHandle, Stream_General, 0, 'Encoded_Library'    , Info_Text, Info_Name);
          TAGs.tgAuthor    := UTF8Decode(S);
        End;

        // Audio Codec & Channels
        {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','*** Audio Codec & Channels');{$ENDIF}
        mChannels := -1;
        aCount    := MediaInfo_Count_Get(miHandle, Stream_Audio, -1);
        {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','Audio Streams : '+IntToStr(aCount));{$ENDIF}
        For I := 0 to aCount-1 do
        Begin
          {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt',IntToStr(I)+'. Audio Stream');{$ENDIF}
          iCodec    := -1;
          //sCommercialName := MediaInfo_Get(miHandle, Stream_Audio, I, 'Format_Commercial_IfAny', Info_Text, Info_Name);
          sFormatString := MediaInfo_Get(miHandle, Stream_Audio, I, 'Format/String' , Info_Text, Info_Name);
          {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt',IntToStr(I)+'. Format String : '+sFormatString);{$ENDIF}
          sFormat       := MediaInfo_Get(miHandle, Stream_Audio, I, 'Format'        , Info_Text, Info_Name);
          {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt',IntToStr(I)+'. Format : '+sFormat);{$ENDIF}
          sProfile      := MediaInfo_Get(miHandle, Stream_Audio, I, 'Format_Profile', Info_Text, Info_Name);
          {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt',IntToStr(I)+'. Profile : '+sProfile);{$ENDIF}
          iChannels     := MediaInfo_AudioChannelCount(MediaInfo_Get(miHandle, Stream_Audio, I, 'Channel(s)', Info_Text, Info_Name));
          {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt',IntToStr(I)+'. Channels : '+IntToStr(iChannels));{$ENDIF}

          iCodec    := MediaInfo_AudioCodecToNavIcon(sFormat,sProfile,sFormatString);

          If (iChannels > mChannels) or
             ((iconAudio = ni_codecDD       ) and (iCodec in [ni_codecDTS,ni_codecDTS_ES,ni_codecDTS_HD_MA,ni_codecDD_TrueHD] = True)) or
             ((iconAudio = ni_codecDTS      ) and (iCodec in [ni_codecDTS_ES,ni_codecDTS_HD_MA,ni_codecDD_TrueHD] = True)) or
             ((iconAudio = ni_codecDTS_ES   ) and (iCodec in [ni_codecDTS_HD_MA,ni_codecDD_TrueHD] = True)) or
             ((iconAudio = ni_codecDD_TrueHD) and (iCodec in [ni_codecDTS_HD_MA] = True)) then
          Begin
            mChannels    := iChannels;
            iconChannels := MediaInfo_AudioChannelsToNavIcon(mChannels);
            iconAudio    := MediaInfo_AudioCodecToNavIcon(sFormat,sProfile,sFormatString);
          End;
        End;
      End;
      {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','Close Handle');{$ENDIF}
      MediaInfo_Close(miHandle);
    End;
  End;
  {$IFDEF LOCALTRACE}DebugMsgFT('c:\log\MediaInfoThread_'+IntToStr(grabThreadID)+'.txt','MediaInfo_GetMediaInfo (after)'+CRLF);{$ENDIF}
end;


function MediaInfo_ProccessTAGdata(FileName : WideString; mRec : TZPFileClass; var albumArt : TBitmap) : Boolean;
var
  miHandle       : Cardinal;
  sImage         : String;
  sDecoded       : String;
  fStream        : TMemoryStream;
  S              : String;

begin
  Result         := False;

  If MediaInfoLoaded = True then
  Begin
    miHandle        := MediaInfo_New;
    If MediaInfo_Open(miHandle, PWideChar(FileName)) = 1 then
    Begin
      sImage := MediaInfo_Get(miHandle, Stream_General, 0, 'Cover_Data'  , Info_Text, Info_Name);

      If sImage <> '' then
      Begin
        sDecoded := Base64DecodeString(sImage);
        Result   := True;
        fStream  := TMemoryStream.Create;
        fStream.Write(sDecoded[1],Length(sDecoded));
        fStream.Position := 0;
        LoadDetectedImage(fStream,albumArt);
        fStream.Free;
      End;

      S := MediaInfo_Get(miHandle, Stream_General, 0, 'Track'  , Info_Text, Info_Name);
      If S = '' then S := MediaInfo_Get(miHandle, Stream_General, 0, 'Movie'  , Info_Text, Info_Name);

      If mRec.zplTAG.tgTitle = '' then
      Begin
        If S = '' then mRec.zplTAG.tgTitle := mRec.zplName else mRec.zplTAG.tgTitle := UTF8Decode(S);
      End;

      S := MediaInfo_Get(miHandle, Stream_General, 0, 'Genre'              , Info_Text, Info_Name);
      If (S <> '') and (mRec.zplTAG.tgGenre     = '') then mRec.zplTAG.tgGenre     := UTF8Decode(S);

      S := MediaInfo_Get(miHandle, Stream_General, 0, 'Track/Position'     , Info_Text, Info_Name);
      If (S <> '') and (mRec.zplTAG.tgTrack     = '') then mRec.zplTAG.tgTrack     := FillZero(S,2);

      S := MediaInfo_Get(miHandle, Stream_General, 0, 'Performer'          , Info_Text, Info_Name);
      If (S <> '') and (mRec.zplTAG.tgArtist    = '') then mRec.zplTAG.tgArtist    := UTF8Decode(S);

      S := MediaInfo_Get(miHandle, Stream_General, 0, 'Album'              , Info_Text, Info_Name);
      If (S <> '') and (mRec.zplTAG.tgAlbum     = '') then mRec.zplTAG.tgAlbum     := UTF8Decode(S);

      S := MediaInfo_Get(miHandle, Stream_General, 0, 'Recorded_Date'      , Info_Text, Info_Name);
      If (S <> '') and (mRec.zplTAG.tgYear      = '') then mRec.zplTAG.tgYear      := UTF8Decode(S);

      S := MediaInfo_Get(miHandle, Stream_General, 0, 'WrittenBy'          , Info_Text, Info_Name);
      If (S <> '') and (mRec.zplTAG.tgAuthor    = '') then mRec.zplTAG.tgAuthor    := UTF8Decode(S);

      S := MediaInfo_Get(miHandle, Stream_General, 0, 'Encoded_Application', Info_Text, Info_Name);
      If S = '' then
      S := MediaInfo_Get(miHandle, Stream_General, 0, 'Encoded_Library'    , Info_Text, Info_Name);

      If (S <> '') and (mRec.zplTAG.tgEncoder   = '') then mRec.zplTAG.tgEncoder   := UTF8Decode(S);

      S := MediaInfo_Get(miHandle, Stream_General, 0, 'Comment'            , Info_Text, Info_Name);
      If (S <> '') and (mRec.zplTAG.tgComment   = '') then mRec.zplTAG.tgComment   := UTF8Decode(S);

      S := MediaInfo_Get(miHandle, Stream_General, 0, 'Track/Url'          , Info_Text, Info_Name);
      If (S <> '') and (mRec.zplTAG.tgURL       = '') then mRec.zplTAG.tgURL       := UTF8Decode(S);

      S := MediaInfo_Get(miHandle, Stream_General, 0, 'Copyright'          , Info_Text, Info_Name);
      If (S <> '') and (mRec.zplTAG.tgCopyright = '') then mRec.zplTAG.tgCopyright := UTF8Decode(S);

      SendLCDs(2400,strNoMoreData);
    End;
    MediaInfo_Close(miHandle);
  End;
end;

Share this post


Link to post

@Remy Lebeau Debugging multiple threads is very difficult (at least in D7) as the run-point seems to jump between the threads each time you advance one line (unless there's something I'm missing?)

This is why I use a lot of debug log entries.

 

I believe the code I pasted above doesn't synchronize anything with the main thread, it's passing data to another (scraping) thread which works (synchronizes) just fine when doing other heavy work unrelated to mediainfo.

 

Share this post


Link to post
7 hours ago, Yaron said:

I believe the code I pasted above doesn't...

If everything was as you believed then there wouldn't be a problem.

The debugger behavior you describe is the same for all versions and is as expected. If you don't want the OS to switch threads during single step then you need to suspend the other threads in the debugger.

 

But you don't really need to single step to locate the problem. Just repeatedly pause the application when it exhibit the behavior you describe and examine the call stacks of the different threads. Sooner or later you will get a snapshop that reveals the cause of the problem. This simple approach almost always work for me.

  • Like 1

Share this post


Link to post
On 3/29/2020 at 3:16 PM, Yaron said:

While MediaInfoThread.IsSuspended = False do Sleep(1);

So you repeat sleeping in the main thread until bg thread becomes suspended again? o_O

 

Side note: unless you analyze 100s of mediafiles at the same time, reusing of thread seems just like a useless complexification.

Share this post


Link to post

@eivindbakkestuen:

I have a 4 Core/8 Thread GPU and the CPU is not really tasked, I believe it's mostly disk I/O.

 

@Fr0sT.Brutal:

You missed the bit where I wrote that the mediainfo data is synched with a central scrape-coordination thread, so the main UI is only disturbed when all the data has been scraped. And yes, it can be analyzing 100's (even 1000's) of files, trying to do so for about 4 concurrently.

 

Share this post


Link to post

Anyway `While MediaInfoThread.IsSuspended = False do Sleep(1); ` looks very suspicious to me, like useless wasting CPU cycles.

Share this post


Link to post
10 hours ago, Fr0sT.Brutal said:

Anyway `While MediaInfoThread.IsSuspended = False do Sleep(1); ` looks very suspicious to me, like useless wasting CPU cycles.

Agreed.  If IsSuspended were a manual-reset Event or ConditionalVariable, the main thread could sleep on it more efficiently.  Or, on Windows 8+, you can use WaitOnAddress() to make the main thread sleep while it waits for the boolean to change value.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×