실행중인 모든 프로세스의 목록을 확인하는 명령어
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
...
START: 프로세스 시작 시각
TIME: 시스템자원을 사용한 시간
COMMAND: 프로세스 실행을 위해 사용한 명령어를 의미함
fork() — 동일 프로그램 처리를 여러 프로세스에서 처리 | 다른 프로그램 생성
부모가 fork()
자식용 메모리 영역 확보 후 그곳에 부모 프로세스의 메모리를 복사 ** 가벼운 작업이라서 동일 작업을 여러 프로세스로 나누는 것은 오버헤드가 크지는 않다.
부모 프로세스에서 fork 값은 자식 프로세스의 pid 값이다. 프로세스 id는 항상 0보다 큰 값을 가지기 때문에, 부모 프로세스에서 받은 fork와 자식 프로세스에서 받은 fork의 값을 가지고,
해당 프로세스가 부모인지 자식인지를 알 수 있다. (자식 프로세스는 fork의 반환값이 0이된다.)
execve() — 다른 프로그램 생성 . 즉 위의 명령어로 프로세스의 복사본을 만들었다면, 이 명령어는 해당 프로세스의 메모리를 새로운 프로그램의 메모리로 덮어씌워주는 역할을 한다.
package main
import (
"log"
"os"
"os/exec"
"time"
)
func main() {
log.Println("Starting process...", os.Args)
// We use command-line arguments to distinguish between the parent and child processes.
switch os.Args[len(os.Args)-1] {
case "child":
// This block runs if the program is executed with "child" as the last argument.
// It's the code for the **child process**.
log.Printf("Child process (PID: %d) - Parent PID: %d\\n", os.Getpid(), os.Getppid())
// The child can perform its specific tasks here.
// For demonstration, we'll have it sleep for a bit.
time.Sleep(30 * time.Second)
log.Printf("Child process (PID: %d) exiting.\\n", os.Getpid())
default:
// This block runs if the program is executed without "child" as the last argument.
// It's the code for the **parent process**.
// Prepare the command to run itself again, but with "child" appended to the arguments.
cmd := exec.Command(os.Args[0], append(os.Args[1:], "child")...)
log.Println("Executing child process with command:", cmd)
// **Forking happens here**: Start the new process.
err := cmd.Start()
if err != nil {
log.Printf("Error starting child process: %v\\n", err)
return
}
log.Printf("Parent process (PID: %d) - Child PID: %d\\n", os.Getpid(), cmd.Process.Pid)
// Optionally, the parent can wait for the child to finish.
// If you remove this, the parent will exit immediately and the child will continue running.
_, err = cmd.Process.Wait()
if err != nil {
log.Printf("Error waiting for child process: %v\\n", err)
}
log.Printf("Parent process (PID: %d) exiting.\\n", os.Getpid())
}
}
/*실행방법
go build main.go
$ ./main.exe
2025/08/02 14:04:44 Starting process... [C:\\Users\\samsung\\Desktop\\linux_study\\cmd\\main.exe]
2025/08/02 14:04:44 Executing child process with command: C:\\Users\\samsung\\Desktop\\linux_study\\cmd\\main.exe child
2025/08/02 14:04:45 Parent process (PID: 13400) - Child PID: 12884
2025/08/02 14:05:15 Parent process (PID: 13400) exiting. -- 지정한 30초 만큼 대기 후 종료가 되는 것으로 보아서 자식 프로세스가 실행이 되긴 된다는 의미다.
*/
golang에서는 이 같은 방식으로 새로운 프로세스를 fork 가능..
package main
import (
"fmt"
"os"
"os/exec"
// Only used for the 'sleep' example on Unix, or just to show timing
)
func main() {
fmt.Println("This is the original Go process (PID:", os.Getpid(), ")")
// Determine which command to run based on the operating system
var cmdName string
var cmdArgs []string
if os.Getenv("GOOS") == "windows" {
cmdName = "cmd.exe"
cmdArgs = []string{"/C", "start", "notepad.exe"} // Launches notepad and detaches
} else {
cmdName = "ls"
cmdArgs = []string{"-l", "/tmp"}
}
fmt.Printf("Attempting to launch '%s %v' and then exit...\\n", cmdName, cmdArgs)
cmd := exec.Command(cmdName, cmdArgs...)
// Start the new process
err := cmd.Start()
if err != nil {
fmt.Printf("Error starting process '%s': %v\\n", cmdName, err)
os.Exit(1)
}
fmt.Printf("Launched new process with PID: %d. Original Go process (PID: %d) is now exiting.\\n", cmd.Process.Pid, os.Getpid())
os.Exit(0) // Exit the Go program
}
---
$ go run main.go
This is the original Go process (PID: 13964 )
Attempting to launch 'ls [-l /tmp]' and then exit...
Launched new process with PID: 2680. Original Go process (PID: 13964) is now exiting.
execev 가 여기서는 cmd.Start에 해당한다.