2013-11-25 8 views
5

jestem w systemie Windows uruchomiony skrypt Perl, który wywołuje plik wykonywalny:Perl interpreter wiersza poleceń nie wychodząc

$command = "$path_to_exe -i $dir -o $results"; 
my $pid = fork(); 

    if (!$pid) { 
     system($command); 

     #do stuff 

    } else { 
     #do stuff 
    } 

print "Exiting..." 
exit; 

Zamiast po wyjściu, perl.exe tylko na biegu jałowym. Wyskakujące okienko mówi mi, że "interpreter wiersza poleceń Perla przestał działać."

Nie wiem zbyt wiele na temat zarządzania procesami w systemie Windows i na tym forum już przeczytałem, że nie jest dobrą praktyką używanie fork() i exec(), ale kod działa dobrze poza tłumaczem, który nie zamyka części. Próbowałem już wszystkiego, od próby zaimplementowania programu w systemie Unix (który daje ten sam błąd) do używania poleceń Win32::Process - ale nic nie działa. Miałem nadzieję, że może istnieć prostsze rozwiązanie, które pozwoli mi zachować to, co już napisałem.

Jeśli ktoś mógłby wyjaśnić, co dokładnie dzieje się w systemie Windows, gdy ten kod jest uruchamiany, to też byłoby pomocne!

+0

widelec-Exec nie jest dobra praktyka na wygraną, bo wygrana nie jest zoptymalizowany do niego. Win jest zoptymalizowany pod kątem ogromnego gwintowania i lokalnego rpc. Ale w twoim przypadku nie jest to prawdziwy problem, ponieważ dla ciebie nie jest tak naprawdę ważne, że twój skrypt owijki generuje 0,001 lub 0,01. Było to ważne tylko wtedy, gdy masz na przykład demona serwera baz danych lub coś, co trzeba nazwać tysiąc razy na sekundę. Inną rzeczą, że tak, fork() - exec() jest powolna, ale fork() - system() jest jeszcze tak powolna ... Widzę dalej, że po prostu nie zareagowałeś na mój drugi problem ($ pid i nie $$). Powinieneś być kooperatywny. – peterh

Odpowiedz

4

Widzę 2 niezależne problemy.

  1. system() tworzy proces potomny, więc jeśli nazywają system() z rozwidloną dziecko, będziesz miał 3 procesy. Ale zabijasz tylko drugą (rozwidlone dziecko), a dziecko dziecka (polecenie $) nie. Spróbuj użyć jakiejś funkcji, takiej jak exec(), na unixie uruchamia proces potomny w miejscu (i na pidzie) rzeczywistego procesu. Jeśli masz szczęście, Perl w Windows robi to samo.

  2. w wątku rodzica zabiłeś $$, który jest bieżącym procesem. Prawdopodobnie chciałeś zabić $pid (który jest pid procesu potomnego w wątku nadrzędnym).

+0

Eksperymentowałem z exec() i odkryłem, że również nie wychodzi. Spróbuję jeszcze raz i zobaczę, co się stanie.'$ pid' w Windows nie jest' $ pid' procesu potomnego, jest liczbą ujemną, która, jak sądzę, odpowiada "pseudoprocesowi". W jakiś sposób sposób, w jaki użyłem 'taskkill' jest funkcjonalny, nie pytaj mnie jak. Dzięki – user86895

+0

Myślę, że twoja droga do przetrwania jest, jeśli zatrzymasz ślepe strzelanie i zaczniesz celować dłońmi i oczami. – peterh

1

użyłem następujących (IT razy na programie, a co najważniejsze, nie łamie interpreter Perla!):

use Win32::Job; 
my $job = Win32::Job->new; 

    # Run $command for $max_time 
    $job->spawn($Config{"path/cmd.exe"}, $command); 
    $job->run($max_time); 
    exit; 
1

w moim przypadku usunąłem kilka "użytkowania" i oświadczenia został rozwiązany. Prawdopodobnie dzieje się tak dlatego, że implementacja Perla dla "widelca" w systemie Windows nie jest idealna i ma problemy z importowaniem jakiegoś "ciężkiego" obiektu, takiego jak biblioteka OLE.

Dokładne zastosowania usunąłem:

#use Win32::OLE qw(in with); 
#use Win32::OLE::Const 'Microsoft Excel'; 

Obejście: jeśli to możliwe, spróbuj import dynamicznie biblioteki po punkcie nie ma widelec w kodzie.

Przykład moim przypadku:

# code with fork 
eval "use Win32::OLE::Const 'Microsoft Excel';"; 
eval "use Win32::OLE qw(in with);"; 
# code without fork