Domanda

Ho un progetto che pensavo sarebbe stato relativamente semplice, ma si sta rivelando più di un dolore che avevo sperato. Innanzitutto, la maggior parte del codice con cui interagisco è un codice legacy sul quale non ho il controllo, quindi non posso fare grandi cambiamenti di paradigma.

Ecco una spiegazione semplificata di cosa devo fare: supponiamo di avere un gran numero di programmi semplici che leggono da stdin e scrivono su stdout. (Questi non li posso toccare). Fondamentalmente, l'input a stdin è un comando come "Imposta temperatura su 100". o qualcosa di simile. E l'output è un evento "La temperatura è stata impostata su 100" o "quot" La temperatura è scesa al di sotto del setpoint ".

Quello che mi piacerebbe fare è scrivere un'applicazione in grado di avviare un mucchio di questi semplici programmi, guardare gli eventi e quindi inviare i comandi a loro, se necessario. Il mio piano iniziale era qualcosa di simile a popen, ma ho bisogno di un popen bidirezionale per ottenere sia la lettura che la scrittura delle pipe. Ho hackerato qualcosa insieme che chiamo popen2 dove gli passo il comando per eseguire e due FILE * che vengono riempiti con il flusso di lettura e scrittura. Quindi tutto ciò che devo fare è scrivere un semplice ciclo che legge da ciascuno degli stdouts da ciascuno dei processi, fa la logica di cui ha bisogno e quindi riscrive i comandi nel giusto processo.

Ecco alcuni pseudocodici

FILE *p1read, *p1write;
FILE *p2read, *p2write;
FILE *p3read, *p3write;

//start each command, attach to stdin and stdout
popen2("process1",&p1read,&p1write);
popen2("process2",&p2read,&p2write);
popen2("process3",&p3read,&p3write);

while (1)
{
   //read status from each process
   char status1[1024];
   char status2[1024];
   char status3[1024];
   fread(status1,1024,p1read);
   fread(status2,1024,p2read);
   fread(status3,1024,p3read);

   char command1[1024];
   char command2[1024];
   char command3[1024];
   //do some logic here

   //write command back to each process
   fwrite(command1,p1write);
   fwrite(command2,p2write);
   fwrite(command3,p3write);
}

Il vero programma è più complicato dove sbircia nello stream per vedere se qualcosa è in attesa, in caso contrario, salterà quel processo, allo stesso modo se non è necessario inviare un comando a un determinato processo, non lo fa . Ma questo codice dà l'idea di base.

Ora funziona benissimo sulla mia scatola UNIX e anche abbastanza bene su una scatola di Windows XP con cygwin. Tuttavia, ora devo farlo funzionare nativamente su Win32.

La parte difficile è che il mio popen2 usa fork () ed execl () per avviare il processo e assegnare i flussi a stdin e stdout dei processi figlio. C'è un modo pulito per farlo in Windows? Fondamentalmente, vorrei creare un popen2 che funzioni in Windows allo stesso modo della mia versione unix. In questo modo l'unico codice specifico di Windows sarebbe in quella funzione e potrei cavarmela con tutto il resto allo stesso modo.

Qualche idea?

Grazie!

È stato utile?

Soluzione

Su Windows, devi invocare prima CreatePipe (simile a pipe (2)), quindi CreateProcess. Il trucco qui è che CreateProcess ha un parametro in cui è possibile passare stdin, stdout, stderr del processo appena creato.

Si noti che quando si utilizza stdio, è necessario eseguire fdopen per creare successivamente l'oggetto file, che prevede i numeri di file. In Microsoft CRT, i numeri di file sono diversi dagli handle di file del sistema operativo. Quindi, per restituire l'altra estremità di CreatePipe al chiamante, è necessario innanzitutto _open_osfhandle per ottenere un numero di file CRT, quindi eseguirne la ricerca.

Se vuoi vedere il codice funzionante, dai un'occhiata a _PyPopen in

http://svn.python.org /view/python/trunk/Modules/posixmodule.c?view=markup

Altri suggerimenti

Penso che tu abbia fatto un'ottima partenza al tuo problema usando la funzione popen2 () per sottrarre i problemi multipiattaforma. Mi aspettavo di venire e suggerire "prese", ma sono sicuro che non è rilevante dopo aver letto la domanda. È possibile utilizzare socket invece di pipe: sarebbe nascosto nella funzione popen2 ().

Sono sicuro al 99% che puoi implementare la funzionalità richiesta su Windows, usando le API di Windows. Quello che non posso fare è indicarti le funzioni giuste in modo affidabile. Tuttavia, dovresti essere consapevole che Microsoft ha la maggior parte delle chiamate API simili a POSIX disponibili, ma il nome è preceduto da '_'. Esistono anche chiamate API native che ottengono gli effetti di fork e exec .

I tuoi commenti suggeriscono che sei a conoscenza di problemi con la disponibilità dei dati e possibili deadlock - sii prudente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top