Linux 프로세스에는 6가지 상태가 있습니다. 1. R 실행 가능 상태, 이 상태의 프로세스만 CPU에서 실행될 수 있습니다. 2. S 인터럽트 가능한 절전 상태, 이 상태의 프로세스는 특정 이벤트가 발생하기를 기다리고 있습니다. 3. D 무중단 슬립 상태, 프로세스는 슬립 상태이지만 현재 프로세스는 중단할 수 없습니다. 4. T 일시 정지 상태 또는 추적 상태는 프로세스에 SIGSTOP 신호를 보내고 신호에 응답합니다. T 상태, 5. Z 좀비 상태, 프로세스가 곧 종료됨을 나타냅니다. 6. X 종료 상태.
이 튜토리얼의 운영 환경: linux7.3 시스템, Dell G3 컴퓨터.
Linux에서 프로세스에는 실행 가능 상태, 중단 가능한 절전 상태, 중단 불가능한 절전 상태, 일시 중지 상태 또는 추적 상태, 좀비 상태, 작동 불능 상태 등 6가지 상태가 있습니다.
Linux 프로세스 상태에 대한 자세한 설명
R(TASK_RUNNING) 실행 가능 상태
이 상태의 프로세스만 CPU에서 실행될 수 있습니다. 동시에 실행 가능한 상태의 여러 프로세스가 있을 수 있으며, 이러한 프로세스의 task_struct 구조(프로세스 제어 블록)는 해당 CPU의 실행 가능 큐에 배치됩니다(프로세스는 한 CPU의 실행 가능 큐에만 나타날 수 있음). 최대). 프로세스 스케줄러의 임무는 각 CPU의 실행 큐에서 해당 CPU에서 실행할 프로세스를 선택하는 것입니다.
많은 운영 체제 교과서에서는 CPU에서 실행 중인 프로세스를 RUNNING 상태로 정의하고, 실행 가능하지만 아직 실행이 예약되지 않은 프로세스를 READY 상태로 정의합니다. 이 두 상태는 Linux에서 TASK_RUNNING 상태로 통합됩니다.
S(TASK_INTERRUPTIBLE) 중단 가능한 절전 상태
이 상태의 프로세스는 특정 이벤트(소켓 연결 대기, 세마포 대기 등)가 발생하기를 기다리고 있기 때문에 일시 중단됩니다. 이러한 프로세스의 task_struct 구조는 해당 이벤트의 대기 큐에 배치됩니다. 이러한 이벤트가 발생하면(외부 인터럽트에 의해 트리거되거나 다른 프로세스에 의해 트리거됨) 해당 대기 큐에 있는 하나 이상의 프로세스가 깨어납니다.
ps 명령을 통해 정상적인 상황에서 프로세스 목록에 있는 대부분의 프로세스가 TASK_INTERRUPTIBLE 상태에 있음을 알 수 있습니다(머신의 부하가 매우 높지 않은 한). 결국 CPU는 한두 개 뿐이고 프로세스가 수십, 수백 개가 있는 경우도 많습니다. 대부분의 프로세스가 절전 모드에 있지 않다면 CPU는 어떻게 응답할 수 있을까요?
D(TASK_UNINTERRUPTIBLE) 무정전 슬립 상태
TASK_INTERRUPTIBLE 상태와 유사하게 프로세스는 슬립 상태이지만 현재는 프로세스를 중단할 수 없습니다. 무정전이란 CPU가 외부 하드웨어의 인터럽트에 응답하지 않는다는 의미가 아니라 프로세스가 비동기 신호에 응답하지 않는다는 의미입니다.
대부분의 경우 프로세스는 절전 상태에 있을 때 항상 비동기 신호에 응답할 수 있어야 합니다. 그렇지 않으면, kill -9가 수면 프로세스를 종료할 수 없다는 사실에 놀랄 것입니다! 따라서 ps 명령으로 표시된 프로세스가 TASK_UNINTERRUPTIBLE 상태로 거의 나타나지 않고 항상 TASK_INTERRUPTIBLE 상태로 나타나는 이유를 쉽게 이해할 수 있습니다.
TASK_UNINTERRUPTIBLE 상태의 중요성은 커널의 특정 처리 흐름을 중단할 수 없다는 것입니다. 비동기 신호에 응답하면 비동기 신호를 처리하는 프로세스가 프로그램의 실행 프로세스에 삽입됩니다(이 삽입된 프로세스는 커널 모드에만 존재할 수도 있고 사용자 모드로 확장될 수도 있음). 방해를 받다.
프로세스가 특정 하드웨어에서 작동하는 경우(예를 들어 프로세스가 특정 장치 파일을 읽기 위해 읽기 시스템 호출을 호출하고 읽기 시스템 호출이 결국 해당 장치 드라이버의 코드를 실행하고 해당 물리적 장치와 상호 작용함) 프로세스와 장치 간의 상호 작용이 중단되어 장치가 제어할 수 없는 상태에 빠지는 것을 방지하기 위해 TASK_UNINTERRUPTIBLE 상태를 사용하여 프로세스를 보호해야 할 수도 있습니다. 이 경우 TASK_UNINTERRUPTIBLE 상태는 항상 매우 짧으며 기본적으로 ps 명령을 통해 캡처하는 것이 불가능합니다.
Linux 시스템에는 캡처하기 쉬운 TASK_UNINTERRUPTIBLE 상태도 있습니다. vfork 시스템 호출을 실행한 후 상위 프로세스는 하위 프로세스가 종료 또는 exec를 호출할 때까지 TASK_UNINTERRUPTIBLE 상태로 들어갑니다.
T(TASK_STPPED 또는 TASK_TRACED) 일시 중지 상태 또는 추적 상태
프로세스에 SIGSTOP 신호를 보내면 프로세스는 신호에 대한 응답으로 TASK_STOPPED 상태로 들어갑니다(프로세스 자체가 TASK_UNINTERRUPTIBLE 상태에 있고 그렇지 않은 경우는 제외). 신호에 응답합니다). (SIGSTOP은 SIGKILL 신호와 마찬가지로 매우 필수입니다. 사용자 프로세스는 신호 시리즈 시스템 호출을 통해 해당 신호 처리 기능을 재설정하는 것이 허용되지 않습니다.)
프로세스에 SIGCONT 신호를 보내면 TASK_STOPPED 상태에서 TASK_STOPPED 상태로 복원될 수 있습니다. TASK_RUNNING 상태.
프로세스를 추적 중인 경우에는 TASK_TRACED라는 특수 상태에 있습니다. "추적 중"은 프로세스가 일시 중지되어 추적 중인 프로세스가 작동할 때까지 기다리는 것을 의미합니다. 예를 들어, gdb에서 추적되는 프로세스에 중단점을 설정하면 프로세스가 중단점에서 중지될 때 프로세스가 TASK_TRACED 상태가 됩니다. 다른 경우에는 추적된 프로세스가 여전히 앞서 언급한 상태에 있습니다.
프로세스 자체의 경우 TASK_STOPPED 및 TASK_TRACED 상태는 매우 유사하며 둘 다 프로세스가 일시 중지되었음을 나타냅니다.
TASK_TRACED 상태는 TASK_STOPPED 위에 추가 보호 계층을 추가하는 것과 같습니다. TASK_TRACED 상태의 프로세스는 SIGCONT 신호에 응답하여 활성화될 수 없습니다. 디버깅된 프로세스는 디버깅 프로세스가 ptrace 시스템 호출을 통해 PTRACE_CONT 및 PTRACE_DETACH와 같은 작업을 수행하거나(작업은 ptrace 시스템 호출의 매개변수를 통해 지정됨) 디버깅 프로세스가 종료될 때까지만 TASK_RUNNING 상태로 돌아갈 수 있습니다.
Z(TASK_DEAD - EXIT_ZOMBIE) 좀비 상태, 프로세스가 좀비 프로세스가 됩니다
프로세스가 종료 프로세스 동안 TASK_DEAD 상태입니다.
이 종료 프로세스 중에 task_struct 구조(및 일부 리소스)를 제외하고 프로세스가 차지하는 모든 리소스가 재활용됩니다. 그래서 프로세스에는 task_struct라는 빈 셸만 남게 되므로 좀비라고 부릅니다.
task_struct가 유지되는 이유는 task_struct가 프로세스의 종료 코드와 일부 통계 정보를 저장하기 때문입니다. 그리고 그 상위 프로세스는 이 정보에 관심을 가질 가능성이 높습니다. 예를 들어 쉘에서 $? 변수는 마지막으로 종료된 포그라운드 프로세스의 종료 코드를 저장하며, 이 종료 코드는 if 문의 판단 조건으로 자주 사용됩니다.
물론 커널은 이 정보를 다른 곳에 저장하고 task_struct 구조를 해제하여 공간을 절약할 수도 있습니다. 하지만 task_struct 구조를 사용하는 것이 더 편리합니다. pid에서 task_struct까지의 검색 관계가 커널에 설정되어 있고 프로세스 간의 부모-자식 관계도 설정되어 있기 때문입니다. task_struct를 해제하려면 상위 프로세스가 하위 프로세스의 종료 정보를 찾을 수 있도록 몇 가지 새로운 데이터 구조를 만들어야 합니다.
상위 프로세스는 일련의 대기 시스템 호출(예: wait4, waitid)을 통해 하나 또는 일부 하위 프로세스의 종료를 기다리고 종료 정보를 얻을 수 있습니다. 그런 다음 일련의 대기 시스템 호출을 통해 하위 프로세스(task_struct)의 본문도 해제됩니다.
자식 프로세스가 종료되면 커널은 부모 프로세스에 신호를 보내 부모 프로세스에 "시체 수집"을 알립니다. 이 신호의 기본값은 SIGCHLD이지만 복제 시스템 호출을 통해 하위 프로세스를 생성할 때 이 신호를 설정할 수 있습니다.
부모 프로세스가 종료되지 않는 한 좀비 상태의 자식 프로세스는 항상 존재합니다. 그렇다면 상위 프로세스가 종료되면 누가 하위 프로세스의 "시체를 수집"합니까?
프로세스가 종료되면 모든 하위 프로세스가 다른 프로세스에 의해 호스팅됩니다(다른 프로세스의 하위 프로세스가 됨). 누구에게 맡겨졌나요? 이는 기존 프로세스(존재하는 경우)의 프로세스 그룹에 있는 다음 프로세스이거나 프로세스 번호 1일 수 있습니다. 따라서 모든 프로세스와 모든 순간에는 상위 프로세스가 있습니다. 프로세스 번호 1이 아닌 이상.
PID가 1인 프로세스 1번을 init 프로세스라고도 합니다. Linux 시스템이 시작된 후 생성된 첫 번째 사용자 모드 프로세스는 init 프로세스입니다. 여기에는 두 가지 임무가 있습니다.
시스템 초기화 스크립트를 실행하고 일련의 프로세스를 생성합니다(모두 init 프로세스의 자손입니다).
무한 루프에서 하위 프로세스의 종료 이벤트를 기다리고 call waitid 시스템 호출은 "시체 수집" 작업을 완료하는 데 사용됩니다.
init 프로세스는 일시 중지되거나 종료되지 않습니다(이는 커널에서 보장됩니다). 자식 프로세스가 종료되기를 기다리는 동안에는 TASK_INTERRUPTIBLE 상태이고, "복구" 프로세스 중에는 TASK_RUNNING 상태입니다.
X(TASK_DEAD - EXIT_DEAD) 사망 상태, 프로세스가 곧 파괴될 예정입니다
그리고 프로세스는 종료 프로세스 중에 task_struct를 유지하지 못할 수 있습니다. 예를 들어, 이 프로세스는 다중 스레드 프로그램에서 분리 가능한 프로세스입니다.
또는 상위 프로세스는 SIGCHLD 신호 핸들러를 SIG_IGN으로 설정하여 SIGCHLD 신호를 명시적으로 무시합니다. (자식 프로세스의 종료 신호를 SIGCHLD 이외의 신호로 설정할 수 있지만 이는 POSIX 규칙입니다.)
이 시점에서 프로세스는 EXIT_DEAD 종료 상태에 놓이게 됩니다. 즉, 다음 코드는 즉시 프로세스가 완전히 해제됩니다. 따라서 EXIT_DEAD 상태는 수명이 매우 짧고 ps 명령으로 캡처하는 것이 거의 불가능합니다.
프로세스의 초기 상태
프로세스는 일련의 시스템 호출(fork, clone, vfork)을 통해 생성됩니다. 커널(또는 커널 모듈)은 kernel_thread 함수를 통해 커널 프로세스를 생성할 수도 있습니다. . 하위 프로세스를 생성하는 이러한 함수는 기본적으로 동일한 기능을 수행합니다. 즉, 호출 프로세스를 복사하여 하위 프로세스를 얻습니다. (옵션 매개변수를 통해 다양한 리소스를 공유할지 비공개할지 결정할 수 있습니다.)
그러면 호출 프로세스가 TASK_RUNNING 상태이므로(그렇지 않으면 실행 중이 아니면 어떻게 호출할 수 있나요?) 자식 프로세스도 기본적으로 TASK_RUNNING 상태입니다. 또한 시스템 호출 clone 및 커널 함수 kernel_thread도 CLONE_STOPPED 옵션을 허용하여 하위 프로세스의 초기 상태를 TASK_STOPPED로 설정합니다.
프로세스 상태 변경
프로세스가 생성된 후 프로세스가 종료될 때까지 상태가 일련의 변경을 거칠 수 있습니다. 프로세스 상태는 여러 가지가 있지만 프로세스 상태 변경에는 TASK_RUNNING 상태에서 TASK_RUNNING이 아닌 상태로, TASK_RUNNING이 아닌 상태에서 TASK_RUNNING 상태로 두 가지 방향만 있습니다.
즉, TASK_INTERRUPTIBLE 상태의 프로세스에 SIGKILL 신호가 전송되면 프로세스는 먼저 깨어나고(TASK_RUNNING 상태로 진입) SIGKILL 신호에 대한 응답으로 종료됩니다(TASK_DEAD 상태로 변경). TASK_INTERRUPTIBLE 상태에서 직접 종료되지는 않습니다.
깨우기 작업을 수행하는 다른 프로세스(인터럽트 핸들러일 수도 있음)에 의해 프로세스가 TASK_RUNNING이 아닌 상태에서 TASK_RUNNING 상태로 변경됩니다. 깨우기를 수행하는 프로세스는 깨어난 프로세스의 상태를 TASK_RUNNING으로 설정한 다음 해당 task_struct 구조를 CPU의 실행 가능 대기열에 추가합니다. 그러면 활성화된 프로세스는 실행을 예약할 수 있는 기회를 갖게 됩니다.
프로세스가 TASK_RUNNING 상태에서 TASK_RUNNING 상태가 아닌 상태로 변경하는 방법에는 두 가지가 있습니다.
신호에 응답하고 TASK_STOPED 상태로 들어가거나
시스템 호출을 실행하고 TASK_INTERRUPTIBLE 상태로 적극적으로 들어갑니다. nanosleep 시스템 호출 등) 또는 TASK_DEAD 상태(예: 시스템 호출 종료) 또는 시스템 호출을 실행하는 데 필요한 리소스를 충족할 수 없기 때문에 TASK_INTERRUPTIBLE 상태 또는 TASK_UNINTERRUPTIBLE 상태(예: 시스템 호출 선택)로 진입합니다.
분명히 이 두 상황은 모두 프로세스가 CPU에서 실행되는 경우에만 발생할 수 있습니다.
Linux 프로세스 상태 설명
상태 기호 | 상태의 전체 이름 | Description |
---|---|---|
R | TASK_RUNNING | 실행 가능 상태 및 실행 상태(run_queue 대기열의 상태) |
S | TASK_INTERRUPTIBLE | 신호 처리 가능 |
D | TASK_UNINTERRUPTIBLE | 신호 처리 가능, 지연 있음 | T
일시 중지 상태 또는 추적 상태, 신호를 처리할 수 없음, 코드를 실행할 시간적 여유가 전혀 없기 때문에 | Z | |
exit 상태에서는 프로세스가 좀비 프로세스가 됩니다. 즉, 작업 신호에 응답하지 않으며 SIGKILL로 종료할 수 없습니다. |
실행 중인 상태의 task_struct(run_queue)를 대기 중인 큐에 넣는 것을 대기 중인 큐에서 실행 중인 큐로 넣고 CPU에 의해 예약되는 것을 일시 중단 대기(blocking)라고 합니다. 프로세스 깨우기
프로세스가 실행 중일 때 일부 작동 조건이 아직 준비되지 않았기 때문에(예: 네트워크가 필요하지만 네트워크 카드가 작동하지 않거나 IO를 기다려야 하는 경우, 즉, 주변 장치를 사용해야 함) 대기 대기열에 배치되고 task_struct의 상태 비트도 S/D에 대해 변경됩니다. 프로세스가 S/D 상태에 있을 때 주변 장치(예: 네트워크 카드, 디스크 모니터 등)를 사용하기 위해 대기 큐에서 기다리고 있습니다. CPU를 기다리는 큐를 실행 큐라고 하며, 주변 장치를 기다리는 장비를 대기 대기열이라고 합니다 소위 프로세스가 실행될 때 운영상의 필요로 인해 다른 대기열에 있을 수 있습니다다른 대기열에서는 상태가 다릅니다 프로세스가 R에 있을 때 상태, 어떤 종류의 주변 장치가 필요하지만 주변 장치가 사용 중인 경우 상태를 S/D로 변경한 다음 task_struct를 대기 대기열에 넣습니다관련 권장 사항: "Linux 비디오 튜토리얼
"위 내용은 리눅스 프로세스에는 여러 가지 상태가 있습니다의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!