Perl зависает до тех пор, пока не будут выполнены ВСЕ команды system()

Вот пример кода на Perl с ТК:

my $btn_start = $mw->Button(-image => $img_start, -command => \&start)->pack;
MainLoop;


sub start{
my $topWin = $mw -> Toplevel;
my $entry = $topWin->Label(-textvariable=>\my $process)->pack();
$process="start 1st";
system("long_command.exe");
$process.="\nstart 2nd";
system("another_command.exe");
.
.
.
$process.="\nstart nth";
system("ncommand.exe");
}

Проблема в том, что когда я нажимаю на кнопку, окно верхнего уровня открывается только после того, как команды system() заканчивают выполнение (почему они запускаются раньше всего??), более того, $btn_start все еще «активен» в течение всего процесса. Я пытаюсь добиться обновления статуса после каждой команды system().

Вы могли бы посоветовать?

Заранее спасибо, Марк.


person Mark    schedule 15.10.2012    source источник


Ответы (4)


Прежде чем запускать команду system(), добавьте

$mw->update()

утверждение. Что происходит, так это то, что основной цикл время от времени обновляет окна; в вашем случае, прежде чем произойдет следующее запланированное обновление (которое может произойти только тогда, когда start() вернется в основной цикл), вызывается system(), и до тех пор, пока он не вернется, больше ничего не будет выполняться - потому что все выполняется в одном процессе .

Однако, если вы хотите делать все правильно, вы должны разветвить свой процесс. В противном случае ваше приложение не будет реактивным во время выполнения команды.

person January    schedule 15.10.2012

В вашем случае пользовательский интерфейс (кнопки, метки и т. д.) и задачи, которые они запускают (system), выполняются одним и тем же процессом и в одном потоке. Это наивный способ написания программы с графическим интерфейсом.

Чтобы получить желаемый эффект — активный пользовательский интерфейс, в то время как что-то еще происходит в фоновом режиме — вам нужно выяснить, как запустить их одновременно.

person Clinton Pierce    schedule 15.10.2012

[Примечание: у меня нет доступа к работающему Tk, поэтому следующее предположение основано на первых принципах и документации. Вы были предупреждены.]

Tk не возвращает управление для обновления пользовательского интерфейса. Происходит то, что вы создали новый TopLevel, но не вернули управление MainLoop, чтобы разрешить его отрисовку. В конце концов, start возвращается, что возвращает управление MainLoop, который одновременно выполняет все ожидающие обновления.

Если вы хотите, чтобы пользовательский интерфейс обновлялся, пока вы находитесь в середине сабвуфера, вы должны периодически вызывать update на самом внешнем интересном Widget, чтобы передать управление обратно MainLoop для заклинания. В вашем случае это выглядит

$mw->update();

См. также update в perldoc Tk::Widget.

person darch    schedule 15.10.2012
comment
Спасибо за объяснение! - person Mark; 15.10.2012

Проблема в том, что system останавливает все (в том же потоке), ожидая завершения подпроцесса. Это включает в себя остановку обслуживания очереди событий графического интерфейса, которая используется для управления всевозможными вещами (включая перерисовку). Рассмотрите возможность использования модуля Proc::Background. для асинхронного запуска подпроцессов (с обычным таймером, чтобы определить, завершена ли одна задача и должна ли начаться следующая, при условии, что для вашего кода важно выполнение только одного за раз).

person Donal Fellows    schedule 16.10.2012
comment
Я попробовал Proc::Background, но, к сожалению, он тоже все зависает: my $proc=Proc::Background-›new(x264.exe --someParameters someValues); $proc-›ждать; Я делаю что-то неправильно? - person Mark; 18.10.2012