2010-03-11 2 views
7

часть моего кода выглядит следующим образом:Можем ли мы запустить два одновременных не-вложенных цикла в Perl?

while(1){ 
     my $winmm = new Win32::MediaPlayer; 
     $winmm->load('1.mp3'); $winmm->play; $winmm->volume(100); 
     Do Some Stuff; 
     last if some condition is met; 
    } 

Проблема: Я хочу, чтобы музыка всегда, когда я нахожусь в каком-то этапе Do запихнуть в то время цикла. Но длина музыки настолько коротка, что она дойдет до полной остановки, прежде чем я перейду на следующий этап, поэтому хочу, чтобы музыка повторялась, но модуль Win32 :: Mediaplayer, похоже, не имеет режима повтора, поэтому я собираюсь сделать бесконечный цикл для части, играющей музыку. Как это:

while(1){ 
my $winmm = new Win32::MediaPlayer; 
$winmm->load('1.mp3'); $winmm->play; $winmm->volume(100); 
} 
while(2){ 
Do some stuff; 
last if some condition is met 
} 

Но, основываясь на моем знаниях Perl, если я в то время как (1) часть, я никогда не может пойти на некоторое время (2) части. Даже если речь идет о вложенном цикле, я должен что-то сделать, чтобы вырваться из внутреннего цикла, прежде чем перейти к другой части внешнего цикла.

Ответ на мой вопрос «Можем ли мы запустить две одновременные не вложенные петли в Perl?» может быть НЕТ, но я предполагаю, что есть какой-то способ справиться с такой ситуацией. Поправьте меня если я ошибаюсь.

Спасибо как всегда за любые комментарии/предложения :)

UPDATE

Я очень ценю помощь от всех. Спасибо :) Итак, ответ на мой вопрос - ДА, а не НЕТ. Я рад, что я узнал, как пользоваться вилкой() и темы, чтобы решить реальную проблему :)

+0

@Mike: Вам нужно только присваивать '$ winmm' один раз, см. Мой ответ ниже. – Zaid

+0

@ Zaid, спасибо, что указали это :) – Mike

ответ

10

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

Что-то вдоль линий:

use strict; 
use warnings; 
use threads; 
use threads::shared; 
use Win32::MediaPlayer; 


my $killAudio :shared = undef; 
my $audio = threads->create(\&playAudio); 
my $condition = threads->create(\&doSomething,$audio); 
$condition->join(); 

sub playAudio { 

    my $winmm = new Win32::MediaPlayer; 
    $winmm->load('1.mp3') or die 'Could not load file: $!'; 
    $winmm->volume(100); 
    $winmm->play until $killAudio; 
} 

sub doSomething { 
    my $thread = shift; 
    my $conditionMet = undef; 

    while (1) { 
     ($conditionMet,$killAudio) = doSomeStuff(); # set doSomeStuff() to 
                 # return only when 
                 # conditions are met 

     $thread->join() if $killAudio;  # This line will terminate $audio 
     last if $conditionMet; 
    } 
} 

UPDATE

Основываясь на комментарий Майка ниже, playAudio() подпрограмму можно переписать в виде:

sub playAudio { 
    my $winmm = new Win32::MediaPlayer; 
    $winmm->load('1.mp3') or die 'Could not load file: $!'; 
    while (1) { 
     $winmm->play; 
     $winmm->volume(100); 
     sleep($winmm->length/1000); 
     last if $killAudio; 
    } 
} 
+0

@ Zaid, это также выглядит очень перспективным решением моей проблемы. Большое спасибо. Я тоже попробую эту резьбу. Спасибо :) – Mike

+0

@Mike: Проверьте также изменения и комментарии к коду. – Zaid

+0

@Mike: Также обратите внимание на 'playAudio()' sub, создание новой '$ winmm' не нужно для каждой итерации цикла while. Я обновил код, чтобы отразить это. – Zaid

6

Вы можете попробовать вилкой, как это:

Так вы будете создавать 2 темы, один из который будет воспроизводить вашу музыку, а второй сделает все остальное.

Вы также должны думать о прекращении музыкальной нить некоторым условием

my @child_pids =(); 
    my $pid = fork(); 
    if ($pid) 
    { 
     # parent 
     push(@child_pids, $pid); 
     Do some stuff; 
     last if some condition is met 
    } 
    elsif ($pid == 0) 
    { 
     # child 
     while(1){ 
     my $winmm = new Win32::MediaPlayer; 
     $winmm->load('1.mp3'); $winmm->play; $winmm->volume(100); 
     } 
     exit(0); 
    } 
    else 
    { 
     die "couldn’t fork: $!\n"; 
    } 
+0

@ user278023, спасибо, спасибо, это похоже на очень хорошее решение :) Спасибо большое! – Mike

+1

Добро пожаловать. У меня есть слегка обновленный код: теперь вы можете использовать сохраненные pids, чтобы убить дочерний процесс в родительском при необходимости. – Miollnyr

+0

@ user278023, благодаря вашему ответу, я рад, что научился использовать fork() для решения реальной проблемы. Однако у меня была небольшая проблема с этим модулем Win32 :: Mediaplayer.Чтобы повторить воспроизведение музыки, я должен закодировать цикл while (1) следующим образом: $ winmm-> load ('1.mp3'); $ Winmm-> играть; $ Winmm-> объем (100); сон (4); Музыка длится около 4 секунд в тесте, без этой сна (4) линия, музыка просто отказывается играть. Ну, я рад, что наконец-то я получил скрипт :) Спасибо. – Mike

2

Если doSomething() этап припадки естественно, внутри петлевой структуры, вы можете просто проверить статус периодической песни союзником и seek назад к началу, если песня закончилась - по общему признанию, взломать, но легко.

use strict; 
use warnings; 

use Win32::MediaPlayer; 
my $winmm = Win32::MediaPlayer->new; 

$winmm->load($ARGV[0]) or die $!; 
$winmm->play; 
my $end_of_song = $winmm->length; 

# doSomething 
for (1 .. 1000){ 
    # Perform difficult computations... 
    sleep 2; 

    # Has song ended? 
    $winmm->seek(0) if $winmm->pos >= $end_of_song; 
} 
+0

+1 для решения без потоков, не нужно добавлять больше сложности, чем необходимо –

+0

@FM, это также выглядит работоспособным. Спасибо :) – Mike

+0

@FM, по-вторых, нет. это не соответствует законопроекту. песня заканчивается до того, как заканчиваются сложные вычисления. Я хочу, чтобы песня была включена, пока не закончились сложные вычисления. – Mike