arden has asked for the wisdom of the Perl Monks concerning the following question:

Please help!!! I have written a program in Perl on Win32 which creates a backup archive and adds some large database files to it. It works fine, but it takes over 10 minutes to run on a high-end machine, and when you look in task-manager it states the program is "Not Responding". When the backup routine is completed, it returns to normal status. The problem is that my users will think the program is truly locked up and kill the app.

Does anyone know how to tell Perl to respond to operating system calls so as to appear fine?

Thanks!
Arden.

Replies are listed 'Best First'.
Re: Application Not Responding
by traveler (Parson) on Feb 27, 2003 at 23:23 UTC
    You can avoid this by having the compute intensive part of the application (your backup it sounds like) run the "main loop" (or "event loop") of your GUI library (Wx, Tk, native win32, Gtk, whatever). If you do this, Explorer (the MS "window manager" can see the app as still alive. Unfortunately, that may require re-designing the backup code so it can call the event handler/main loop. I had to do this redesign when converting a command-line app to a GUI app.

    tachyon's ideas are good and any widget you invoke that prints a progress bar or whatever will (should?) call the event loop at the appropriate intervals. How you do it really depends on your toolkit.

    HTH, --traveler

Re: Application Not Responding
by tachyon (Chancellor) on Feb 27, 2003 at 23:15 UTC

    Make it print dots or have a - / | \ rotating widget? Print a message saying this will take a while? Background it (close/hide the console/GUI widget) so you users forget about it, then pop a done! console/gui?

    You can set $SIG handlers but these are not re-enterant so you probably don't really want to do that.

    Is it a console or a GUI app?

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Application Not Responding
by arden (Curate) on Feb 27, 2003 at 23:43 UTC
    Ok, I obviously should have said more. My app is compiled using PerlApp. It is a very simple Perl/Tk widget which has three buttons: backup, restore, and exit; each calls a subroutine to handle the action.

    Backup subroutine shutsdown an Oracle 8i database, creates a .zip archive, and puts the contents of two arrays (filenames) into the archive and writes the .zip file. The first array is a list of the database files (these range from 50 MB to 400 MB in size), the second array are user files such as output reports and queries which are almost all less than 50 KB. It does not show a progressbar because it takes less than a second to add all the files to the zip archive (the loop) but it takes over ten minutes to complete the command $zip->writeToFileNamed($new_zip_file). While this one command is running, NT shows my app as "Not responding".

    Restore opens a top-level widget with a listbox allowing the user to choose which backup to restore. When they select one and press the "OK" button, it shuts down the database unless it's already shutdown, builds an array with the name of every file in the archive and then extracts each one displaying a progress bar based on the number of files extracted '$percent_done = int(($file_num / $total_files) * 100)'. Even with the progressbar up, the application shows as "Not responding".

    Exit restarts the database if it was shutdown and then destroys the widget.

      What you need to do is create a subprocess. If this were C/C++, you would create a thread, but I don't think you can do that with Perl/TK on Windows.

      Anyway, the subprocess does all the time-consuming stuff and sends back progress/error/completion reports via an IPC mechanism (e.g. a socket). You can use Tk::Event->fileevent for the parent process to get these notifications. Meanwhile the parent process is responding to normal window messages.

      Update: Well, I spoke too soon. fork() blows chunks with Perk/Tk under Win32 and fileevent doesn't work either (althought it may "soon"). You can create a subprocess using Win32::Process. For one approach to IPC, see this.

      As all you need is an indication of when the task is finished, you can fork a subprocess and write the file from there leaving the parent process to maintain the gui and report when the background process has completed.

      This works fine under AS 5.6.1 and 5.8, whether PerlApp can handle it I have no experience.


      ..and remember there are a lot of things monks are supposed to be but lazy is not one of them

      Examine what is said, not who speaks.
      1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
      2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
      3) Any sufficiently advanced technology is indistinguishable from magic.
      Arthur C. Clarke.
        Thanks all for your help. I've gotten around my problem for this particular case by delving deep into other people's modules. Basically, I re-wrote the Archive::Zip module so that I could pass it two new variables ($window_handle & $percent_done_reference). Then, after every chunk of data is written out to file, I redo the math for percentage done $$percent_done_reference = 100*($total_size - $self->_readDataRemaining)/$total_size; and then update the window $window_handle->update();. The update happens often enough that my program very rarely falls into "Not Responding" status. I happen to also be using the $percent_done variable in a progress bar. :)

        Again, thanks for the help!
        Arden