2009-05-23 10 views
6

Ho sentito spesso che usare system("PAUSE") è una cattiva pratica e usare invece std::cin.get(). Ora la mia comprensione delle chiamate di sistema è che prendono una stringa che inseriscono in una riga di comando del sistema e parlano con il sistema operativo, quindi PAUSE è un comando DOS che mette in pausa l'output nella finestra di comando. Presumo che funzioni in modo simile a Mac e unix con parole chiave diverse e che l'utilizzo delle chiamate di sistema sia scoraggiato a causa della mancanza di compatibilità cross-OS. (Se mi sbaglio in tutto questo, correggimi)System() chiama in C++ e i loro ruoli nella programmazione

la mia domanda è questa: quando è opportuno utilizzare le chiamate di sistema()? Come dovrebbero essere applicati? Quando non dovrebbero essere applicati?

+4

Quindi, come è andata, all'improvviso hai pensato "hey, è davvero giunto il momento di apportare alcune modifiche estetiche a una domanda presentata più di un anno fa"? :) –

risposta

29

system("PAUSE") è certamente meno che ideale. l'utilizzo di una chiamata al sistema crea un sottoprocesso, che su Windows è piuttosto costoso e in ogni caso non eccessivamente economico su nessun sistema operativo. Sui sistemi embedded l'overhead della memoria è significativo.

Se c'è un modo per farlo senza molto dolore in modo nativo, allora fallo. Nel caso in cui si desideri che l'utente preme un singolo pulsante, cin.get() sarà molto difficile da battere. In questo caso, il processo delle applicazioni bloccherà solo su stdin, impostando solo pochi flag visibili al kernel e, soprattutto, non alloca nuova memoria e non crea nuove entità di pianificazione, nemmeno un gestore di interrupt.

Inoltre, funzionerà allo stesso modo su tutti i sistemi operativi con tutti i compilatori C++, poiché utilizza solo una funzione di base di una parte molto standard della lingua, piuttosto che dipendere da tutto ciò che il SO fornisce.

MODIFICA: prevedi la tua preoccupazione che non importa se è costoso perché l'intera idea è di mettere in pausa. Bene, prima di tutto, se è costoso, allora danneggerà le prestazioni per qualsiasi altra cosa che potrebbe accadere. Mai notato (su Windows) all'avvio di un'applicazione, anche altre app già aperte diventano meno reattive? Inoltre, il tuo utente potrebbe non essere un live human, ma piuttosto un altro programma che lavora per conto di un utente umano (Say, uno script di shell). Lo script sa già cosa fare dopo e può pre-riempire lo stdin con un personaggio per saltare l'attesa. Se hai utilizzato un sottoprocesso qui, lo script subirà un ritardo (evidente da un essere umano). Se lo script esegue centinaia di volte (o centinaia di milioni!) Di volte, uno script che potrebbe richiedere secondi per essere eseguito richiede ora giorni o anni.

EDIT2: quando usare system(): quando è necessario fare qualcosa che fa un altro processo, che non è possibile fare facilmente. system() non è sempre il miglior candidato perché fa due cose che sono un po 'limitanti. Innanzitutto, l'unico modo per comunicare con il sottoprocesso è tramite gli argomenti della riga di comando come input e il valore restituito come output. Il secondo è che il processo genitore blocca fino al completamento del processo figlio. Questi due fattori limitano i casi in cui il sistema è utilizzabile.

su sistemi unixy, la maggior parte dei sottoprocessi si verifica con fork perché consente allo stesso programma di continuare nello stesso posto di due processi separati, uno come figlio dell'altro (che è quasi impercettibile a meno che non venga richiesto dal sistema operativo). Su Linux, questo è particolarmente ben ottimizzato e conveniente quanto la creazione di un pthread. Anche su sistemi dove non è così veloce, è ancora molto utile (come dimostrato dalla metodologia del pool di processi apache) (non disponibile su windows/link to unix docs)

altri casi (anche su Windows!) Sono spesso gestiti da popen o exec famiglia di funzioni.popen crea un sottoprocesso e una nuova pipa che si collega allo stdin o allo stdout dei sottoprocessi. Entrambi i processi padre e figlio possono quindi essere eseguiti contemporaneamente e comunicare abbastanza facilmente. (link to windows docs/link to unix docs)

exec * famiglia di funzioni (ci sono diversi, execl, execv e così via) dall'altro provoca il programma aggiornato da sostituire dal nuovo programma. Il programma originale esce invisibilmente e il nuovo processo prende il sopravvento. Quando poi il nuovo processo ritorna, ritornerà a quello che ha chiamato il processo originale, come se quel processo fosse ritornato a quel punto invece di scomparire. Il vantaggio di questo corso exit(system("command")) è che non viene creato nessun nuovo processo, il tempo e la memoria (anche se non sempre terribilmente molto) (link to windows docs/link to unix docs) risparmio

system potrebbe plausibilmente essere utilizzato da qualche strumento di script per richiamare diversi passaggi in qualche ricetta azione. Ad esempio, a un certo punto, un programma potrebbe utilizzare system per richiamare un editor di testo per modificare alcuni file di configurazione. Non deve preoccuparsi troppo di ciò che accade, ma dovrebbe certamente aspettare fino a quando l'utente non ha salvato e chiuso l'editor prima di continuare. Può quindi utilizzare il valore di ritorno per scoprire se la sessione di modifica ha avuto esito positivo, nel senso che l'editor ha effettivamente aperto il file richiesto (e che l'editor stesso esisteva del tutto!), Ma leggerà i risultati effettivi della sessione da il file modificato direttamente, piuttosto che comunicare con il sottoprocesso. (link to windows docs/link to unix docs)

+0

Esiste qualche differenza nella gestione delle variabili di ambiente tra exec e system? –

+0

@Thomas L Holaday: alcune varianti di exec consentono di specificare diverse variabili di ambiente, altre utilizzano l'ambiente corrente. il sistema usa sempre l'ambiente corrente. – SingleNegationElimination

1

Per quanto ne so il sistema ("PAUSE") è una cosa solo per Windows, ed è per questo che è disapprovato.

3

Le chiamate di sistema vengono inviate alla shell o all'interprete di riga di comando del sistema operativo (dos, bash, ecc.) E fino alla shell per fare ciò che desidera con questo comando.

Si eviterà di utilizzare questo tipo di chiamate in quanto ridurrebbe la portabilità dei programmi per funzionare con altri sistemi operativi. Penserei solo quando sei assolutamente sicuro che il tuo codice abbia come target un sistema operativo specifico che dovresti utilizzare per tali chiamate.

3

Ma la mia domanda è questa: quando è opportuno utilizzare le chiamate di sistema()? Come dovrebbero essere applicati?

Quando non si può fare la cosa che si sta tentando di fare con il proprio codice o una libreria (o il costo di implementazione supera il costo di avviare un nuovo processo per farlo). system() è piuttosto costoso in termini di risorse di sistema rispetto a cin.get(), e come tale dovrebbe essere usato solo quando assolutamente necessario. Ricorda che system() in genere lancia sia un'intera nuova shell e qualunque programma tu abbia chiesto che venga eseguito, così che vengono lanciati due nuovi eseguibili.

1

system() viene utilizzato per chiedere al sistema operativo di eseguire un programma.

Perché il programma desidera che il sistema operativo esegua un programma? Bene, ci sono casi. A volte un comando esterno del programma o del sistema operativo può eseguire un compito difficile da eseguire nel proprio programma. Ad esempio, un programma esterno può operare con privilegi elevati o accedere a formati di dati proprietari.

La funzione system(), a sua volta, è abbastanza portatile ma la stringa di comando che si passa è probabile che sia molto specifica della piattaforma, anche se la stringa di comando può essere estratta dai dati di configurazione locali per renderla più indipendente dalla piattaforma.

Altre funzioni come fork(), exec*(), spawn*() e CreateProcess() vi darà molto più controllo sul modo in cui si esegue il programma esterno, ma sono specifici della piattaforma e potrebbero non essere disponibili sulla propria piattaforma di scelta.

system("PAUSE") è un vecchio trucco DOS ed è generalmente considerato uno stile abbastanza brutto in questi giorni.

2

A proposito, sistema() chiamata non dovrebbe mai essere utilizzato con i binari con SUID o SGID bit impostato, citando il man page:

Non utilizzare il sistema() da un programma con i privilegi set-user-ID o set-group-ID , perché potrebbero essere usati strani valori per alcune variabili d'ambiente per sovvertire l'integrità del sistema. Utilizzare invece la famiglia exec (3) delle funzioni , ma non execlp (3) o execvp (3). system() no, , infatti, funziona correttamente dai programmi con set-user-ID o set-group-ID privilegi sui sistemi su cui/bin/sh è bash versione 2, poiché bash 2 rilascia i privilegi all'avvio.