2015-02-06 14 views
6

Ich möchte einen Go-Prozess abzweigen und die ID des neuen Prozesses zurückbekommen, aber alles, was ich in den exec oder os Bibliotheken sehen kann, ist einen neuen Prozess zu starten.Wie mache ich einen Go-Prozess?

Antwort

19

Sie wollen angeblich syscall.ForkExec() vom syscall Paket.

Beachten Sie, dass fork() zu der Zeit erfunden wurde, als überhaupt keine Threads verwendet wurden, und ein Prozess hatte immer nur einen einzigen Thread der Ausführung in sich, und daher war die Verzweigung sicher. Mit Go ist die Situation radikal anders, da es in hohem Maße Threads auf Betriebssystemebene verwendet, um die Routineplanung zu beschleunigen.

Nun schmucklos fork(2) auf Linux wird das Kind Prozess machen müssen nur die einzelnen Thread — derjenige, der fork(2) in den übergeordneten Prozess — unter all diejenigen genannt, die aktiv waren, darunter auch einige wichtige Themen von der Go-Laufzeit verwendet. Im Grunde bedeutet dies, dass Sie einfach nicht erwarten können, dass das Kind process in der Lage sein wird, weiterhin Go-Code, auszuführen, und das einzige, was Sie sinnvollerweise tun können, ist, sofort durchzuführen exec(2). Beachten Sie, dass syscall.ForkExec() für verwendet wird.

Und nun über das Problem weiter denken. Ich würde sagen, in diesen Tagen die einzige Sache, die ein direkter Anruf zu fork(2) ist nützlich für "best-work asynchronen Prozess State Snapshotting" — der Art, sagen Redis verwendet. Diese Technik beruht auf der Tatsache, dass der Kindprozess alle Speicherdatenseiten von seinem Elternteil erbt, aber das Betriebssystem verwendet die Copy-on-Write-Technik, um nicht wirklich alle Daten zu kopieren, so dass das Kind einfach dort sitzen und alle Datenstrukturen speichern kann auf Platte, während sein Elternteil weg tuckert und sie in seinem eigenen Adressraum ändert. Jede andere denkbare Verwendung für fork() impliziert sofortige exec(), und das ist, was exec.Command() et al ist, warum also einfach nicht verwenden?

+4

"Jede andere denkbare Verwendung von fork() impliziert sofortiges exec(), und dafür ist exec.Command() et al. Warum also einfach nicht verwenden?" Es gibt setrlimit(), das Einrichten von SELinux, chroot() ing, das Schließen oder Einrichten von FDs vor der Übergabe der Kontrolle - und das muss zwischen fork() und exec() passieren, nein? –

+0

Was ist, wenn "Best-Effort asynchrone Prozessstatus-Snapshotting" * genau * ist, was ich versuche zu tun? – cpcallen

+1

@cpcallen, ich fürchte, das wäre "nicht in Go" * so. * Das Problem ist, dass die Go-Laufzeit zwei Dinge zu den OS-Level-Threads macht: a) verwendet sie, um Ihre Goroutines anzutreiben ; b) benutzt sie für ihre eigenen Bedürfnisse.Da nur ein einziger Thread eine 'fork()' überlebt, wird er, sobald er in einem neuen Prozess wieder aufgenommen wird, in einem halb-assestierten Zustand sein, was unmöglich ist, richtig zu arbeiten. – kostix

0

Eine Lösung ist die Verwendung einer exec.Command in ihrer Goroutine ausgeführt.

Das ist, was das kleine Projekt akshaydeo/go_process tut:

// Method to fork a process for given command 
// and return ProcessMonitor 
func Fork(processStateListener ProcessStateListener, cmdName string, cmdArgs ...string) { 
    go func() { 
     processMonitor := &ProcessMonitor{} 
     args := strings.Join(cmdArgs, ",") 
     command := exec.Command(cmdName, args) 
     output, err := command.Output() 
     if err != nil { 
      processMonitor.Err = err 
      processStateListener.OnError(processMonitor, err) 
     }  
     processMonitor.Output = &output 
     processStateListener.OnComplete(processMonitor) 
    }() 
} 

The test process_test.go zeigt einige Beispiele:

// Test case for fork 
func TestFork(t *testing.T) { 
    processStateListenerImpl := &ProcessStateListenerImpl{make(chan bool)} 
    Fork(processStateListenerImpl,"ls", "-a") //("ping","192.168.3.141","-c","3") 
    // waiting onto monitor 
    <-processStateListenerImpl.monitor 
} 
+0

Es ist Forking 'ls' Prozess. Ich möchte den gleichen Prozess forkieren, den ich gerade betreibe. Wie kann ich das tun - 'Gabelung von' C++ '? – Shashwat

+0

@Shashwat nicht sicher: Ich habe nur das Gegenteil gesehen (http://StackOverflow.com/q/22805059/6309) – VonC

+0

Ich rate hier: Es gibt eine 'Rückkehr' fehlt im' if err! = Nil' Block von 'Gabel'. –