podemos executar duas voltas simultânea não-aninhados em Perl?
-
19-09-2019 - |
Pergunta
Parte do meu código é assim:
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;
}
O problema é: eu quero que a música seja sempre quando estou no palco fazer alguma coisas no loop while. Mas o comprimento da música é tão curta que ele vai chegar a uma paragem completa antes de eu ir para a próxima fase, então eu quero a música a se repetir, mas o módulo Win32 :: Mediaplayer não parecem ter um modo de repetição, assim que eu estou pensando em fazer um loop infinito para a parte a reprodução de música. Como esta:
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
}
Mas, com base no meu conhecimento atual Perl se eu estou no (1) parte enquanto, eu nunca pode ir para o while (2) parte. Mesmo se se trata de um loop aninhado, eu tenho que fazer alguma coisa para sair do loop dentro antes de ir para a outra parte do circuito exterior.
A resposta à minha pergunta "Podemos executar dois loops não-aninhados simultâneas em Perl?" pode ser um não, mas eu suponho que há alguma maneira de lidar com tal situação. Corrija-me se eu estiver errado.
Graças como sempre para quaisquer comentários / sugestões:)
Atualizar
Eu realmente aprecio a ajuda de todos. Obrigado :) Portanto, a resposta para a minha pergunta é um sim, não um NO. Estou feliz que eu aprendi como usar fork () e tópicos para resolver um problema real:)
Solução
Você pode executar os dois processos diferentes em segmentos separados.
Algo ao longo das linhas de:
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;
}
}
Atualizar
Com base no comentário de Mike abaixo, a sub-rotina playAudio()
pode ser reescrita como:
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;
}
}
Outras dicas
Pode tentar garfo, como este:
Assim que você vai criar 2 tópicos, um dos quais irão desempenhar a sua música e segundo vai fazer todas as suas outras coisas.
Você também deve pensar em terminar seu segmento de música por alguma condição
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";
}
Se seus doSomething()
estágio se encaixa naturalmente dentro de uma estrutura de loop, você pode simplesmente verificar o status da canção periodicamente e seek
volta ao início se a canção terminou -. Reconhecidamente um hack, mas fácil
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;
}