Linux를 예로 들어 UNIX 계열 운영 체제에서의 작동 원리. 나만의 경량 프로세스 만들기

환경에서 다른 환경으로 이동할 때 가장 짜증나는 순간 중 하나 윈도우 기반사용하기위한 명령줄– 쉬운 멀티 태스킹의 상실. Linux에서도 X Window 시스템을 사용하는 경우 마우스를 사용하여 간단히 클릭할 수 있습니다. 새로운 프로그램그리고 그것을 엽니다. 그러나 명령줄에서는 모노태스킹이 거의 불가능합니다. 이 기사에서 우리는 당신에게 보여줄 것입니다 Linux에서 명령줄을 사용하여 멀티태스킹하는 방법

배경 및 우선순위 프로세스 관리

그러나 Linux에는 여전히 멀티태스킹을 수행할 수 있는 방법이 있으며 그 중 일부는 다른 것보다 더 포괄적입니다. 추가가 필요하지 않은 하나의 기본 제공 방법 소프트웨어, 단순히 백그라운드와 포그라운드에서 프로세스를 이동하는 것입니다. 우리는 이것에 대해 이야기하고 있습니다. 그러나 몇 가지 단점이 있습니다.

보호되지 않음

첫째로백그라운드에서 프로세스를 보내려면 먼저 프로세스를 일시 중지해야 합니다. 이미 실행 중인 프로그램을 백그라운드로 보내고 동시에 유지 관리하는 것은 불가능합니다.

둘째, 새 명령을 시작하려면 워크플로를 중단해야 합니다. 현재 수행 중인 작업에서 벗어나 쉘에 더 많은 명령을 입력해야 합니다. 작동하지만 불편합니다.

제삼, 백그라운드 프로세스의 출력을 모니터링해야 합니다. 이들의 모든 출력은 명령줄에 나타나며 현재 수행 중인 작업을 방해합니다. 따라서 백그라운드 작업은 출력을 다음으로 리디렉션해야 합니다. 별도의 파일또는 완전히 비활성화해야 합니다.

이러한 단점으로 인해 배경 및 전경 프로세스를 관리하는 데 큰 문제가 있습니다. 최선의 결정– 아래와 같이 명령줄 유틸리티 "screen"을 사용합니다.

하지만 먼저 새 SSH 세션을 엽니다.

새로운 SSH 세션을 여는 중이라는 사실을 잊지 마세요.

항상 새로운 세션을 여는 것은 불편할 수 있습니다. 바로 그때가 바로 "스크린"이 필요한 때입니다.

공익사업 화면동시에 열려 있는 여러 작업 흐름을 만들 수 있습니다. 이는 "창"과 가장 가까운 아날로그입니다. 기본적으로 일반 Linux 리포지토리에서 사용할 수 있습니다. 다음 명령을 사용하여 CentOS/RHEL에 설치합니다.

Sudo yum 설치 화면

새 화면 열기

이제 "screen"을 입력하여 세션을 시작하세요.

이것은 생성됩니다 빈 창기존 SSH 세션 내에서 다음과 같이 헤더에 표시되는 번호를 제공합니다.

여기 화면에는 표시된 대로 "0"으로 번호가 매겨져 있습니다. 이 스크린샷에서는 더미 "읽기" 명령을 사용하여 터미널을 차단하고 입력을 기다리게 합니다. 이제 기다리는 동안 다른 일을 하고 싶다고 가정해 보겠습니다.

열기 위해 새 화면다른 작업을 수행하면 다음과 같이 인쇄됩니다.

Ctrl+a c

“ctrl+a”는 화면 프로그램에서 화면을 제어하기 위한 기본 키 조합입니다. 입력한 후에 입력하는 내용에 따라 작업이 결정됩니다. 예를 들어:

  • Ctrl + A C – 새 화면을 활성화합니다
  • Ctrl+A [숫자]– 특정 화면 번호로 이동
  • Ctrl + A K - 케이현재 화면 꺼줘
  • ctrl+a n - 화면으로 이동 N
  • ctrl+a “- 세션의 모든 활성 화면을 표시합니다.

"ctrl+a c"를 누르면 새 번호가 포함된 새 화면이 표시됩니다.

커서 키를 사용하여 목록을 탐색하고 원하는 화면으로 이동할 수 있습니다.
화면은 명령의 시스템처럼 "창"에 가장 가깝습니다. 리눅스 문자열. 물론 마우스를 클릭하는 것만큼 간단하지는 않지만 그래픽 하위 시스템은 리소스 집약적입니다. 화면을 사용하면 거의 동일한 기능을 얻을 수 있으며 완전한 멀티태스킹이 가능합니다!

UNIX의 프로세스

UNIX에서 멀티태스킹의 주요 구성 수단이자 단위는 프로세스입니다. 운영 체제는 프로그램 코드를 나타내는 프로세스 이미지와 실행 환경을 정의하는 프로세스 데이터 섹션을 조작합니다.

실행 중 또는 대기 중 프로세스는 페이지 구성과 함께 가상 메모리에 포함됩니다. 이 가상 메모리 중 일부는 실제 메모리에 매핑됩니다. 실제 메모리의 일부는 운영 체제 커널용으로 예약되어 있습니다. 사용자는 프로세스에 남아 있는 메모리에만 액세스할 수 있습니다. 필요한 경우 프로세스 메모리 페이지가 물리적 메모리에서 디스크, 스왑 영역으로 스왑됩니다. 가상 메모리에 있는 페이지에 접근할 때, 물리 메모리에 없는 페이지는 디스크에서 스왑됩니다.

가상 메모리는 UNIX 커널에 의해 구현되고 자동으로 유지 관리됩니다.

프로세스 유형

UNIX 운영 체제에는 세 가지 유형의 프로세스가 있습니다. 전신의, 데몬 프로세스그리고 신청 절차.

시스템 프로세스핵의 일부이며 항상 위치합니다. 랜덤 액세스 메모리. 시스템 프로세스에는 실행 파일 형태의 해당 프로그램이 없으며 시스템 커널이 초기화될 때 특별한 방법으로 시작됩니다. 이러한 프로세스의 실행 명령과 데이터는 시스템의 커널에 있으므로 다른 프로세스가 액세스할 수 없는 기능을 호출하고 데이터에 액세스할 수 있습니다.

시스템 프로세스에는 초기 초기화 프로세스, 초기화, 이는 다른 모든 프로세스의 조상입니다. 하지만 초기화커널의 일부가 아니며 실행 파일에서 실행이 발생하므로 해당 작업은 전체 시스템의 기능에 필수적입니다.

악마- 이는 해당 프로그램을 메모리에 로드하여 일반적인 방식으로 시작되고 백그라운드에서 실행되는 비대화형 프로세스입니다. 일반적으로 데몬은 시스템 초기화 중에 시작되지만 커널이 초기화된 후에는 터미널 액세스 시스템, 인쇄 시스템 등 다양한 UNIX 하위 시스템의 작동을 확인합니다. 네트워크 서비스등. 악마는 어떤 사용자와도 연관되어 있지 않습니다. 대부분의 경우 데몬은 하나의 프로세스 또는 다른 프로세스가 요청하기를 기다립니다. 특정 서비스.



에게 신청 절차시스템에서 실행 중인 다른 모든 프로세스를 포함합니다. 일반적으로 이는 사용자 세션 내에서 생성된 프로세스입니다. 가장 중요한 사용자 프로세스는 초기 명령 해석기, UNIX 시스템에서 사용자 명령 실행을 제공합니다.

사용자 프로세스는 대화형(선점형) 및 배경 모드. 대화형 프로세스는 터미널에 대한 독점 소유권을 가지며 해당 프로세스가 실행을 완료할 때까지 사용자는 명령줄에 액세스할 수 없습니다.

프로세스 속성

UNIX 프로세스에는 다음을 수행할 수 있는 여러 가지 속성이 있습니다. 운영 체제업무를 관리합니다. 주요 속성:

· 프로세스 ID(PID), 시스템 커널이 프로세스를 구별할 수 있도록 합니다. 생성 시 새로운 프로세스, 커널은 다음 자유(즉, 어떤 프로세스와도 연관되지 않음) 식별자를 할당합니다. 식별자 할당은 일반적으로 오름차순으로 발생합니다. 새 프로세스의 ID는 이전에 생성된 프로세스의 ID보다 큽니다. ID가 최대값(보통 65737)에 도달하면 다음 프로세스는 최소 여유 PID를 수신하고 주기가 반복됩니다. 프로세스가 종료되면 커널은 사용 중이던 식별자를 해제합니다.

· 상위 프로세스 ID(PPID)– 이 프로세스를 생성한 프로세스의 식별자입니다. 다음을 제외한 시스템의 모든 프로세스 시스템 프로세스그리고 처리 초기화나머지 프로세스의 조상인 은 기존 또는 이전에 존재했던 프로세스 중 하나에 의해 생성됩니다.

· 우선순위 수정(NI)– 시작 순서를 결정할 때 스케줄러가 고려하는 프로세스의 상대적 우선순위입니다. 프로세서 리소스의 실제 배포는 실행 우선 순위(속성)에 따라 결정됩니다. PRI), 여러 요인, 특히 주어진 상대적 우선순위에 따라 달라집니다. 상대적 우선순위는 프로세스가 진행되는 동안 시스템에 의해 변경되지 않습니다. 단, 명령을 사용하여 프로세스를 시작할 때 사용자나 관리자가 변경할 수는 있습니다. 멋진. 대부분의 시스템에서 우선순위 증가값의 범위는 -20~20이며, 증가값을 지정하지 않을 경우 기본값인 10이 사용되며, 양수 증가는 현재 우선순위가 감소함을 의미합니다. 일반 사용자는 양의 증분만 설정할 수 있으므로 우선 순위만 낮출 수 있습니다. 사용자 뿌리음의 증분을 설정할 수 있으며, 이는 프로세스의 우선순위를 높여서 프로세스의 우선순위를 높이는 데 기여합니다. 빠른 작업. 상대적 우선순위와 달리 프로세스의 실행 우선순위는 스케줄러에 의해 동적으로 변경됩니다.

· 터미널 라인(TTY)– 프로세스와 관련된 터미널 또는 의사 터미널. 이 터미널은 표준과 연결되어 있습니다. 스트림: 입력, 휴일그리고 메시지 흐름오류에 대해. 스트림( 프로그램 채널) 이다 표준 수단 UNIX OS의 프로세스 간 통신. 데몬 프로세스는 터미널과 연결되어 있지 않습니다.

· 실제(UID) 및 유효(EUID) 사용자 식별자. 특정 프로세스의 실제 사용자 ID는 해당 프로세스를 시작한 사용자의 ID입니다. 유효 식별자는 시스템 리소스(주로 리소스)에 대한 프로세스의 액세스 권한을 결정하는 데 사용됩니다. 파일 시스템). 일반적으로 실제 식별자와 유효 식별자는 동일합니다. 프로세스는 이를 실행한 사용자와 시스템에서 동일한 권한을 갖습니다. 그러나 다음을 설정하여 프로세스에 사용자보다 더 많은 권한을 부여할 수 있습니다. SUID 비트유효 식별자가 실행 파일 소유자의 식별자(예: 사용자)로 설정된 경우 뿌리).

· 실제(GID) 및 유효(EGID) 그룹 식별자입니다.실제 그룹 ID는 프로세스를 시작한 사용자의 기본 또는 현재 그룹 ID와 동일합니다. 유효 식별자는 그룹을 대신하여 시스템 리소스에 대한 액세스 권한을 결정하는 데 사용됩니다. 일반적으로 유효 그룹 ID는 실제 그룹 ID와 동일합니다. 그러나 실행 파일이 다음으로 설정되어 있으면 SGID 비트, 해당 파일은 유효 소유자 그룹 ID로 실행됩니다.

실험실 작업 3번

멀티 태스킹 프로그래밍리눅스

1. 작업의 목표: gcc 컴파일러, 프로그램 디버깅 기술, 프로세스 작업을 위한 기능을 숙지하세요.

2. 간략한 이론적 정보.

gcc 컴파일러 스위치의 최소 세트는 - Wall(모든 오류 및 경고 표시) 및 - o(출력 파일)입니다.

gcc - Wall - o print_pid print_pid. 씨

팀이 만들 것입니다. 실행 가능 파일 print_pid.

C 표준 라이브러리(libc, glibc의 Linux에서 구현됨)는 Unix System V(이하 SysV)의 멀티태스킹 기능을 활용합니다. libc에서 pid_t 유형은 pid를 포함할 수 있는 정수로 정의됩니다. 현재 프로세스의 pid를 보고하는 함수는 pid_t getpid(void)의 프로토타입을 가지며 unistd에서 pid_t와 함께 정의됩니다. h 및 sys/types. 시간).

새 프로세스를 만들려면 포크 기능을 사용하세요.

pid_t 포크(무효)

sleep 및 rand 함수를 사용하여 임의 길이의 지연을 삽입하면 멀티태스킹 효과를 더욱 명확하게 확인할 수 있습니다.

이로 인해 프로그램은 0에서 3까지 임의의 초 동안 "휴면" 상태가 됩니다.

함수를 하위 프로세스로 호출하려면 분기 후에 호출하면 됩니다.

// 자식 프로세스가 실행 중이면 함수를 호출합니다.

pid=프로세스(인수);

// 프로세스 종료

종종 다른 프로그램을 자식 프로세스로 실행해야 하는 경우가 있습니다. 이를 수행하려면 exec 계열 함수를 사용하십시오.

// 자식 프로세스가 실행 중이면 프로그램을 호출합니다.


if (execl("./file","file",arg, NULL)<0) {

printf("프로세스 시작 중 오류가 발생했습니다\n");

else printf("프로세스가 시작되었습니다(pid=%d)\n", pid);

// 프로세스 종료

적시에 작업을 수행하기 위해 상위 프로세스는 하위 프로세스와 정보를 교환하거나 최소한 동기화해야 하는 경우가 많습니다. 프로세스를 동기화하는 한 가지 방법은 wait 및 waitpid 함수를 사용하는 것입니다.

#포함하다

#포함하다

pid_t wait(int *status) - 하위 프로세스가 종료될 때까지 현재 프로세스의 실행을 일시 중지합니다.

pid_t waitpid (pid_t pid, int *status, int 옵션) - 지정된 프로세스가 완료되거나 지정된 프로세스의 완료를 확인할 때까지 현재 프로세스의 실행을 일시 중지합니다.

종료 시 하위 프로세스의 상태와 반환되는 값을 확인해야 하는 경우 WEXITSTATUS 매크로를 사용하여 하위 프로세스의 상태를 매개변수로 전달합니다.

status=waitpid(pid,&status, WNOHANG);

if (pid == 상태) (

printf("PID: %d, 결과 = %d\n", pid, WEXITSTATUS(상태)); )

생성된 프로세스의 우선순위를 변경하려면 setpriority 및 함수가 사용됩니다. 우선순위는 -20(최고)에서 20(최저) 범위로 설정되며 일반 값은 0입니다. 수퍼유저만 일반보다 우선순위를 높일 수 있습니다.

#포함하다

#포함하다

int 프로세스(int i) (

setpriority(PRIO_PROCESS, getpid(),i);

printf("프로세스 %d ThreadID: %d 우선순위 %d로 작업 중\n",i, getpid(),getpriority(PRIO_PROCESS, getpid()));

return(getpriority(PRIO_PROCESS, getpid()));

프로세스를 종료하려면 kill 함수를 사용하십시오.

#포함하다

#포함하다

int kill(pid_t pid, int sig);

pid > 0이면 신호가 전송되는 프로세스의 PID를 지정합니다. pid = 0이면 현재 프로세스가 속한 그룹의 모든 프로세스에 신호가 전송됩니다.

sig - 신호 유형. Linux의 일부 신호 유형:

SIGKILL 이 신호는 프로세스를 즉시 종료시킵니다. 프로세스는 이 신호를 무시할 수 없습니다.

SIGTERM 이 신호는 프로세스를 종료하라는 요청입니다.

SIGCHLD 시스템은 자식 프로세스 중 하나가 종료되면 프로세스에 이 신호를 보냅니다. 예:

if (pid[i] == 상태) (

printf("ThreadID: %d가 %d 상태로 완료되었습니다.\n", pid[i], WEXITSTATUS(status));

그렇지 않으면 kill(pid[i],SIGKILL);

3. 체계적인 지침.

3.1. gcc 컴파일러 옵션과 C 언어 함수 설명에 익숙해지려면 man 및 info 명령어를 사용하세요.

3.2. 프로그램을 디버깅하려면 파일 관리자의 내장 편집기를 사용하는 것이 편리합니다. 미드나잇 커맨더(MC)는 다양한 언어 구성을 색상으로 강조 표시하고 화면 상단 줄에 파일(행, 열)의 커서 위치를 나타냅니다.

3.3. Midnight Commander 파일 관리자에는 키보드 단축키로 호출할 수 있는 명령 버퍼가 있습니다. - H, 커서 화살표(위 및 아래)를 사용하여 이동할 수 있습니다. 버퍼의 명령을 명령줄에 삽입하려면 키를 사용하십시오. , 버퍼에서 명령을 편집하려면 - 키<- и ->, 그리고 .


3.4. 현재 디렉터리는 path에 포함되어 있지 않으므로 명령줄에서 "./print_pid"로 프로그램을 실행해야 합니다. MC에서는 파일 위로 마우스를 가져가서 클릭하세요. .

3.5. 프로그램 실행 결과를 보려면 키보드 단축키를 사용하십시오. - O. 파일 편집 모드에서도 작동합니다.

3.6. 프로그램 실행 결과를 기록하려면 콘솔에서 파일로 출력 리디렉션(./test > result)을 사용하는 것이 좋습니다. txt

3.7. 다음에 생성된 파일에 액세스하려면 리눅스 서버, Windows 2000에서 사용할 수 있고 Windows 2000에 내장된 클라이언트 프로그램인 ftp 프로토콜을 사용합니다. 파일 관리자멀리. 여기서 계정비밀번호는 SSH를 통해 연결할 때와 동일합니다.

4.1. 프로그램 디버깅을 위한 gcc 컴파일러 옵션과 방법을 숙지하세요.

4.2. 실험실 작업 1번의 작업 변형에 대해 생성된 프로세스를 구현하는 프로그램을 작성하고 디버깅합니다.

4.3. 작업 옵션의 경우 실험실 작업 1번은 하위 프로세스(옵션에 따라 프로그램이 완료되거나 삭제될 때까지 기다리는 프로그램)의 상태를 호출하고 모니터링하는 상위 프로세스를 구현하는 프로그램을 작성하고 디버깅합니다.

4.4. 실험실 작업 1번의 작업 변형에 대해 하위 프로세스의 상태를 호출하고 모니터링하는 상위 프로세스를 구현하는 프로그램을 작성하고 디버깅합니다. 즉, 기능(변형에 따라 완료를 기다리거나 파괴함)입니다.

5. 작업에 대한 옵션입니다.실험실 작업 1번 작업에 대한 옵션 보기

6. 보고서의 내용.

6.1. 작업의 목표.

6.2. 작업 옵션.

6.3. 프로그램 목록.

6.4. 프로그램 실행 프로토콜.

7. 통제 질문.

7.1. Linux에서 C 프로그램을 컴파일하고 실행하는 기능입니다.

7.2. pid란 무엇이며 운영 체제와 프로그램에서 어떻게 결정합니까?

7.3. 포크 함수 - 목적, 애플리케이션, 반환 값.

7.4. 생성된 프로세스에서 함수를 실행하는 방법은 무엇입니까? 프로그램?

7.5. 상위 프로세스와 하위 프로세스를 동기화하는 방법.

7.6. 종료 시 생성된 프로세스의 상태와 반환되는 값을 찾는 방법은 무엇입니까?

7.7. 프로세스 우선순위를 관리하는 방법은 무엇입니까?

7.8. 운영 체제 및 프로그램에서 프로세스를 종료하는 방법은 무엇입니까?

우리는 Linux 커널의 멀티스레딩 주제를 계속합니다. 지난번에 중단, 중단 처리 및 태스크릿에 대해 이야기했으며 원래는 하나의 기사로 작성될 예정이었으므로 작업 대기열에 대한 내 이야기에서는 독자가 이미 이에 대해 잘 알고 있다는 가정하에 태스크릿을 참조하겠습니다.
지난번처럼 제 이야기를 최대한 자세하고 자세하게 만들도록 노력하겠습니다.

시리즈의 기사:

  1. Linux 커널의 멀티태스킹: workqueue

작업 대기열

작업 대기열- 태스크릿보다 더 복잡하고 무거운 엔터티입니다. 여기서 구현의 모든 복잡한 사항을 설명하지는 않겠지만 가장 중요한 사항을 어느 정도 자세히 분석할 수 있기를 바랍니다.
태스크릿과 같은 작업 대기열은 지연된 인터럽트 처리에 사용되지만(다른 목적으로 사용될 수 있음) 태스크릿과 달리 커널 프로세스의 컨텍스트에서 실행됩니다. 따라서 원자적일 필요가 없으며 절전 모드를 사용할 수 있습니다. () 기능, 다양한 동기화 도구 등

먼저 작업 대기열 처리 프로세스가 일반적으로 어떻게 구성되어 있는지 이해해 보겠습니다. 그림은 매우 대략적이고 단순화되어 있으며 모든 일이 실제로 어떻게 일어나는지는 아래에 자세히 설명되어 있습니다.

이 암흑물질에는 여러 독립체가 관련되어 있습니다.
첫째로, 작업 항목(Just work for short)는 스케줄링하려는 기능(예: 인터럽트 핸들러)을 설명하는 구조로, 태스크릿 구조와 유사하다고 생각할 수 있습니다. 예약할 때 Tasklet이 사용자에게 숨겨진 대기열에 추가되었지만 이제 특수 대기열을 사용해야 합니다. 작업 대기열.
태스크릿은 스케줄러 기능에 의해 긁어지고 작업 대기열은 작업자라는 특수 스레드에 의해 처리됩니다.
노동자작업 대기열에서 작업의 비동기 실행을 제공합니다. 작업을 회전 순서로 호출하지만 일반적으로 엄격하고 순차적인 실행에 대해서는 의문의 여지가 없습니다. 결국 선점, 절전, 대기 등이 여기에서 발생합니다.

일반적으로 워커는 커널 스레드입니다. 즉, 기본 Linux 커널 스케줄러에 의해 제어됩니다. 그러나 작업자는 병렬 작업 실행의 추가 조직을 계획하는 데 부분적으로 개입합니다. 이에 대해서는 아래에서 더 자세히 설명하겠습니다.

작업 대기열 메커니즘의 주요 기능을 간략하게 설명하려면 API를 살펴보는 것이 좋습니다.

대기열 및 생성 정보

alloc_workqueue(fmt, 플래그, max_active, args...)
매개변수 fmt 및 args는 이름과 그에 대한 인수에 대한 printf 형식입니다. max_activate 매개변수는 이 대기열에서 하나의 CPU에서 병렬로 실행될 수 있는 최대 작업 수를 담당합니다.
다음 플래그를 사용하여 대기열을 만들 수 있습니다.
  • WQ_HIGHPRI
  • WQ_UNBOUND
  • WQ_CPU_집중
  • WQ_FREEZABLE
  • WQ_MEM_RECLAIM
깃발에 특별한주의를 기울여야합니다 WQ_UNBOUND. 이 플래그의 존재 여부에 따라 대기열은 바인딩된 대기열과 연결되지 않은 대기열로 구분됩니다.
연결된 대기열에서추가되면 작업은 현재 CPU에 바인딩됩니다. 즉, 이러한 대기열에서 작업은 이를 예약하는 코어에서 실행됩니다. 이 점에서 바운드 큐는 태스크릿과 유사합니다.
연결되지 않은 대기열에서작업은 모든 코어에서 실행될 수 있습니다.

Linux 커널의 작업 대기열 구현의 중요한 기능은 바인딩된 대기열에 존재하는 병렬 실행의 추가 구성입니다. 아래에 더 자세히 설명되어 있지만 이제는 메모리를 최대한 적게 사용하고 프로세서가 유휴 상태가되지 않도록 수행된다고 말씀 드리겠습니다. 이는 모두 하나의 작업이 너무 많은 프로세서 사이클을 사용하지 않는다는 가정하에 구현됩니다.
연결되지 않은 대기열의 경우에는 해당되지 않습니다. 기본적으로 이러한 대기열은 단순히 작업자에게 컨텍스트를 제공하고 가능한 한 빨리 시작합니다.
따라서 CPU 집약적인 작업 부하가 예상되는 경우 연결되지 않은 대기열을 사용해야 합니다. 이 경우 스케줄러가 여러 코어에서 병렬 실행을 처리하기 때문입니다.

태스크릿과 유사하게 작업에는 보통 또는 높음의 실행 우선순위가 할당될 수 있습니다. 우선순위는 전체 대기열에 공통됩니다. 기본적으로 대기열의 우선순위는 보통이며, 플래그를 설정하면 WQ_HIGHPRI, 그에 따라 높습니다.

깃발 WQ_CPU_집중바운드 큐에만 의미가 있습니다. 이 플래그는 추가 병렬 실행 조직에 참여하는 것을 거부합니다. 이 플래그는 작업이 많은 CPU 시간을 소비할 것으로 예상될 때 사용해야 하며, 이 경우 책임을 스케줄러에게 옮기는 것이 좋습니다. 이에 대해서는 아래에서 자세히 설명합니다.

플래그 WQ_FREEZABLE그리고 WQ_MEM_RECLAIM구체적이고 주제의 범위를 벗어나므로 자세히 설명하지 않겠습니다.

때로는 자신만의 대기열을 생성하지 않고 공통 대기열을 사용하는 것이 합리적일 때도 있습니다. 주요 내용:

  • system_wq - 빠른 작업을 위한 바운드 큐
  • system_long_wq - 실행하는 데 오랜 시간이 걸릴 것으로 예상되는 작업에 대한 바운드 큐
  • system_unbound_wq - 언바운드 큐

일과 계획에 대하여

이제 작품을 다루겠습니다. 먼저 초기화, 선언 및 준비 매크로를 살펴보겠습니다.
DECLARE(_DELAYED)_WORK(name, void (*function)(struct work_struct *work)); /* 컴파일 시 */ INIT(_DELAYED)_WORK(_work, _func); /* 실행 중 */ PREPARE(_DELAYED)_WORK(_work, _func); /* 실행 중인 함수를 변경하려면 */
작품은 다음 기능을 사용하여 대기열에 추가됩니다.
bool queue_work(struct workqueue_struct *wq, struct work_struct *work); bool queue_delayed_work(struct workqueue_struct *wq, struct Delay_work *dwork, unsigned long Delay); /* 작업은 지연이 만료된 후에만 대기열에 추가됩니다 */
이에 대해 더 자세히 살펴볼 가치가 있습니다. 매개변수로 대기열을 지정하더라도 실제로 작업은 작업 대기열 자체에 배치되지 않고 완전히 다른 엔터티, 즉 작업자_풀 구조의 대기열 목록에 배치됩니다. 구조 작업자_풀는 실제로 작업 대기열 메커니즘을 구성하는 데 가장 중요한 엔터티이지만 사용자에게는 보이지 않는 곳에 남아 있습니다. 근로자가 일하는 것은 그들과 함께하며 모든 기본 정보가 포함되어 있습니다.

이제 시스템에 어떤 풀이 있는지 살펴보겠습니다.
우선, 바인딩된 대기열을 위한 풀(그림 참조)입니다. 각 CPU에 대해 두 개의 작업자 풀이 정적으로 할당됩니다. 하나는 우선 순위가 높은 작업용이고 다른 하나는 보통 우선 순위의 작업용입니다. 즉, 4개의 코어가 있으면 원하는 만큼 작업 대기열이 있을 수 있다는 사실에도 불구하고 바인딩된 풀은 8개만 있게 됩니다.
작업 대기열을 생성하면 각 CPU에 할당된 서비스가 있습니다. pool_workqueue(pwq). 이러한 각각의 pool_workqueue는 동일한 CPU에 할당되고 우선순위가 대기열 유형에 해당하는 작업자 풀과 연결됩니다. 이를 통해 작업 대기열은 작업자 풀과 상호 작용합니다.
작업자는 원래 속한 작업 대기열을 구별하지 않고 작업자 풀에서 작업을 무차별적으로 실행합니다.

연결되지 않은 대기열의 경우 작업자 풀이 동적으로 할당됩니다. 모든 대기열은 해당 매개변수에 따라 동등한 클래스로 나눌 수 있으며, 이러한 각 클래스에 대해 자체 작업자 풀이 생성됩니다. 키는 매개변수 세트이고 값은 각각 작업자 풀인 특수 해시 테이블을 사용하여 액세스됩니다.
실제로 바인딩되지 않은 대기열의 경우 모든 것이 조금 더 복잡합니다. 바인딩된 대기열 pwq의 경우 각 CPU에 대해 대기열이 생성된 경우 여기에서는 각 NUMA 노드에 대해 생성되지만 이는 자세히 고려하지 않을 추가 최적화입니다.

온갖 작은 것들

또한 그림을 완성하기 위해 API의 몇 가지 기능을 제공할 것이지만 이에 대해 자세히 설명하지는 않겠습니다.
/* 강제 완료 */ boollush_work(struct work_struct *work); boollush_delayed_work(struct Delayed_work *dwork); /* 작업 실행 취소 */ bool cancel_work_sync(struct work_struct *work); bool cancel_delayed_work(struct Delayed_work *dwork); bool cancel_delayed_work_sync(struct Delayed_work *dwork); /* 큐 삭제 */ void destroy_workqueue(struct workqueue_struct *wq);

근로자가 업무를 수행하는 방법

이제 우리는 API에 익숙해졌으므로 API가 어떻게 작동하고 관리되는지 더 자세히 이해해 보겠습니다.
각 풀에는 작업을 처리하는 작업자 집합이 있습니다. 또한, 근로자 수는 현재 상황에 맞춰 동적으로 변화합니다.
우리가 이미 알아낸 것처럼 워커는 커널 컨텍스트에서 작업을 수행하는 스레드입니다. 작업자는 연결된 작업자 풀에서 순서대로 이를 검색하며, 이미 알고 있듯이 작업자는 다른 소스 대기열에 속할 수 있습니다.

작업자는 조건부로 세 가지 논리적 상태, 즉 유휴 상태, 실행 중, 관리 상태일 수 있습니다.
작업자는 다음과 같이 할 수 있습니다. 가만히 서 있다그리고 아무것도 하지 마세요. 예를 들어 모든 작업이 이미 실행 중인 경우입니다. 워커가 이 상태에 들어가면 휴면 상태가 되며 깨어날 때까지 실행되지 않습니다.
풀 관리가 필요하지 않고 예약된 작업 목록이 비어 있지 않으면 작업자가 해당 작업을 실행하기 시작합니다. 우리는 일반적으로 그러한 근로자를 부를 것입니다 달리기.
필요한 경우 작업자가 역할을 맡습니다. 관리자수영장. 풀에는 관리 작업자가 한 명만 있거나 작업자가 전혀 없을 수 있습니다. 그 임무는 풀당 최적의 작업자 수를 유지하는 것입니다. 그는 어떻게 합니까? 첫째, 장기간 유휴 상태인 작업자가 삭제됩니다. 둘째, 세 가지 조건이 동시에 충족되면 새로운 작업자가 생성됩니다.

  • 아직 완료해야 할 작업이 있습니다(풀에서 작동).
  • 유휴 근로자 없음
  • 일하는 근로자가 없습니다 (즉, 활동적이고 잠을 자지 않습니다)
그러나 마지막 조건에는 고유한 뉘앙스가 있습니다. 풀 대기열이 연결되지 않은 경우 실행 중인 작업자는 고려되지 않습니다. 작업자의 경우 이 조건은 항상 true입니다. 작업자가 연결된 작업에서 작업을 실행하는 경우에도 마찬가지입니다. WQ_CPU_집중, 대기열. 더욱이 묶인 대기열의 경우 작업자는 공통 풀(위 그림의 각 코어에 대해 2개 중 하나)의 작업으로 작업하므로 일부는 작업 중인 것으로 간주되고 일부는 작동하지 않는 것으로 나타났습니다. 또한 다음에서 작업을 수행합니다. WQ_CPU_집중대기열은 즉시 시작되지 않을 수 있지만 대기열 자체는 다른 작업의 실행을 방해하지 않습니다. 이제 이 플래그를 왜 그렇게 부르는지, 작업을 완료하는 데 오랜 시간이 걸릴 것으로 예상할 때 사용되는 이유가 분명해졌습니다.

작업 작업자에 대한 회계는 기본 Linux 커널 스케줄러에서 직접 수행됩니다. 이 제어 메커니즘은 최적의 동시성 수준을 보장하여 작업 대기열이 너무 많은 작업자를 생성하는 것을 방지할 뿐만 아니라 작업이 불필요하게 너무 오랫동안 기다리지 않도록 합니다.

관심 있는 분들은 커널의 작업자 함수(worker_thread())를 살펴보세요.

설명된 모든 기능과 구조는 파일에서 더 자세히 확인할 수 있습니다. include/linux/workqueue.h, 커널/workqueue.c그리고 커널/workqueue_internal.h. workqueue에 대한 문서도 있습니다. 문서/workqueue.txt.

작업 대기열 메커니즘이 지연된 인터럽트 처리에만 사용되는 것이 아니라 커널에서 사용된다는 점도 주목할 가치가 있습니다(비록 이는 매우 일반적인 시나리오임에도 불구하고).

따라서 우리는 멀티태스킹의 특별한 형태인 태스크릿 및 작업 대기열과 같은 Linux 커널의 지연된 인터럽트 처리 메커니즘을 살펴보았습니다. Jonathan Corbet, Greg Kroah-Hartman, Alessandro Rubini가 쓴 "Linux Device Drivers" 책에서 인터럽트, 태스크릿 및 작업 대기열에 대해 읽을 수 있지만 거기에 있는 정보는 때때로 오래된 것일 수도 있습니다.

우리는 Linux 커널의 멀티스레딩 주제를 계속합니다. 지난번에 중단, 중단 처리 및 태스크릿에 대해 이야기했으며 원래는 하나의 기사로 작성될 예정이었으므로 작업 대기열에 대한 내 이야기에서는 독자가 이미 이에 대해 잘 알고 있다는 가정하에 태스크릿을 참조하겠습니다.
지난번처럼 제 이야기를 최대한 자세하고 자세하게 만들도록 노력하겠습니다.

시리즈의 기사:

  1. Linux 커널의 멀티태스킹: workqueue

작업 대기열

작업 대기열- 태스크릿보다 더 복잡하고 무거운 엔터티입니다. 여기서 구현의 모든 복잡한 사항을 설명하지는 않겠지만 가장 중요한 사항을 어느 정도 자세히 분석할 수 있기를 바랍니다.
태스크릿과 같은 작업 대기열은 지연된 인터럽트 처리에 사용되지만(다른 목적으로 사용될 수 있음) 태스크릿과 달리 커널 프로세스의 컨텍스트에서 실행됩니다. 따라서 원자적일 필요가 없으며 절전 모드를 사용할 수 있습니다. () 기능, 다양한 동기화 도구 등

먼저 작업 대기열 처리 프로세스가 일반적으로 어떻게 구성되어 있는지 이해해 보겠습니다. 그림은 매우 대략적이고 단순화되어 있으며 모든 일이 실제로 어떻게 일어나는지는 아래에 자세히 설명되어 있습니다.

이 암흑물질에는 여러 독립체가 관련되어 있습니다.
첫째로, 작업 항목(Just work for short)는 스케줄링하려는 기능(예: 인터럽트 핸들러)을 설명하는 구조로, 태스크릿 구조와 유사하다고 생각할 수 있습니다. 예약할 때 Tasklet이 사용자에게 숨겨진 대기열에 추가되었지만 이제 특수 대기열을 사용해야 합니다. 작업 대기열.
태스크릿은 스케줄러 기능에 의해 긁어지고 작업 대기열은 작업자라는 특수 스레드에 의해 처리됩니다.
노동자작업 대기열에서 작업의 비동기 실행을 제공합니다. 작업을 회전 순서로 호출하지만 일반적으로 엄격하고 순차적인 실행에 대해서는 의문의 여지가 없습니다. 결국 선점, 절전, 대기 등이 여기에서 발생합니다.

일반적으로 워커는 커널 스레드입니다. 즉, 기본 Linux 커널 스케줄러에 의해 제어됩니다. 그러나 작업자는 병렬 작업 실행의 추가 조직을 계획하는 데 부분적으로 개입합니다. 이에 대해서는 아래에서 더 자세히 설명하겠습니다.

작업 대기열 메커니즘의 주요 기능을 간략하게 설명하려면 API를 살펴보는 것이 좋습니다.

대기열 및 생성 정보

alloc_workqueue(fmt, 플래그, max_active, args...)
매개변수 fmt 및 args는 이름과 그에 대한 인수에 대한 printf 형식입니다. max_activate 매개변수는 이 대기열에서 하나의 CPU에서 병렬로 실행될 수 있는 최대 작업 수를 담당합니다.
다음 플래그를 사용하여 대기열을 만들 수 있습니다.
  • WQ_HIGHPRI
  • WQ_UNBOUND
  • WQ_CPU_집중
  • WQ_FREEZABLE
  • WQ_MEM_RECLAIM
깃발에 특별한주의를 기울여야합니다 WQ_UNBOUND. 이 플래그의 존재 여부에 따라 대기열은 바인딩된 대기열과 연결되지 않은 대기열로 구분됩니다.
연결된 대기열에서추가되면 작업은 현재 CPU에 바인딩됩니다. 즉, 이러한 대기열에서 작업은 이를 예약하는 코어에서 실행됩니다. 이 점에서 바운드 큐는 태스크릿과 유사합니다.
연결되지 않은 대기열에서작업은 모든 코어에서 실행될 수 있습니다.

Linux 커널의 작업 대기열 구현의 중요한 기능은 바인딩된 대기열에 존재하는 병렬 실행의 추가 구성입니다. 아래에 더 자세히 설명되어 있지만 이제는 메모리를 최대한 적게 사용하고 프로세서가 유휴 상태가되지 않도록 수행된다고 말씀 드리겠습니다. 이는 모두 하나의 작업이 너무 많은 프로세서 사이클을 사용하지 않는다는 가정하에 구현됩니다.
연결되지 않은 대기열의 경우에는 해당되지 않습니다. 기본적으로 이러한 대기열은 단순히 작업자에게 컨텍스트를 제공하고 가능한 한 빨리 시작합니다.
따라서 CPU 집약적인 작업 부하가 예상되는 경우 연결되지 않은 대기열을 사용해야 합니다. 이 경우 스케줄러가 여러 코어에서 병렬 실행을 처리하기 때문입니다.

태스크릿과 유사하게 작업에는 보통 또는 높음의 실행 우선순위가 할당될 수 있습니다. 우선순위는 전체 대기열에 공통됩니다. 기본적으로 대기열의 우선순위는 보통이며, 플래그를 설정하면 WQ_HIGHPRI, 그에 따라 높습니다.

깃발 WQ_CPU_집중바운드 큐에만 의미가 있습니다. 이 플래그는 추가 병렬 실행 조직에 참여하는 것을 거부합니다. 이 플래그는 작업이 많은 CPU 시간을 소비할 것으로 예상될 때 사용해야 하며, 이 경우 책임을 스케줄러에게 옮기는 것이 좋습니다. 이에 대해서는 아래에서 자세히 설명합니다.

플래그 WQ_FREEZABLE그리고 WQ_MEM_RECLAIM구체적이고 주제의 범위를 벗어나므로 자세히 설명하지 않겠습니다.

때로는 자신만의 대기열을 생성하지 않고 공통 대기열을 사용하는 것이 합리적일 때도 있습니다. 주요 내용:

  • system_wq - 빠른 작업을 위한 바운드 큐
  • system_long_wq - 실행하는 데 오랜 시간이 걸릴 것으로 예상되는 작업에 대한 바운드 큐
  • system_unbound_wq - 언바운드 큐

일과 계획에 대하여

이제 작품을 다루겠습니다. 먼저 초기화, 선언 및 준비 매크로를 살펴보겠습니다.
DECLARE(_DELAYED)_WORK(name, void (*function)(struct work_struct *work)); /* 컴파일 시 */ INIT(_DELAYED)_WORK(_work, _func); /* 실행 중 */ PREPARE(_DELAYED)_WORK(_work, _func); /* 실행 중인 함수를 변경하려면 */
작품은 다음 기능을 사용하여 대기열에 추가됩니다.
bool queue_work(struct workqueue_struct *wq, struct work_struct *work); bool queue_delayed_work(struct workqueue_struct *wq, struct Delay_work *dwork, unsigned long Delay); /* 작업은 지연이 만료된 후에만 대기열에 추가됩니다 */
이에 대해 더 자세히 살펴볼 가치가 있습니다. 매개변수로 대기열을 지정하더라도 실제로 작업은 작업 대기열 자체에 배치되지 않고 완전히 다른 엔터티, 즉 작업자_풀 구조의 대기열 목록에 배치됩니다. 구조 작업자_풀는 실제로 작업 대기열 메커니즘을 구성하는 데 가장 중요한 엔터티이지만 사용자에게는 보이지 않는 곳에 남아 있습니다. 근로자가 일하는 것은 그들과 함께하며 모든 기본 정보가 포함되어 있습니다.

이제 시스템에 어떤 풀이 있는지 살펴보겠습니다.
우선, 바인딩된 대기열을 위한 풀(그림 참조)입니다. 각 CPU에 대해 두 개의 작업자 풀이 정적으로 할당됩니다. 하나는 우선 순위가 높은 작업용이고 다른 하나는 보통 우선 순위의 작업용입니다. 즉, 4개의 코어가 있으면 원하는 만큼 작업 대기열이 있을 수 있다는 사실에도 불구하고 바인딩된 풀은 8개만 있게 됩니다.
작업 대기열을 생성하면 각 CPU에 할당된 서비스가 있습니다. pool_workqueue(pwq). 이러한 각각의 pool_workqueue는 동일한 CPU에 할당되고 우선순위가 대기열 유형에 해당하는 작업자 풀과 연결됩니다. 이를 통해 작업 대기열은 작업자 풀과 상호 작용합니다.
작업자는 원래 속한 작업 대기열을 구별하지 않고 작업자 풀에서 작업을 무차별적으로 실행합니다.

연결되지 않은 대기열의 경우 작업자 풀이 동적으로 할당됩니다. 모든 대기열은 해당 매개변수에 따라 동등한 클래스로 나눌 수 있으며, 이러한 각 클래스에 대해 자체 작업자 풀이 생성됩니다. 키는 매개변수 세트이고 값은 각각 작업자 풀인 특수 해시 테이블을 사용하여 액세스됩니다.
실제로 바인딩되지 않은 대기열의 경우 모든 것이 조금 더 복잡합니다. 바인딩된 대기열 pwq의 경우 각 CPU에 대해 대기열이 생성된 경우 여기에서는 각 NUMA 노드에 대해 생성되지만 이는 자세히 고려하지 않을 추가 최적화입니다.

온갖 작은 것들

또한 그림을 완성하기 위해 API의 몇 가지 기능을 제공할 것이지만 이에 대해 자세히 설명하지는 않겠습니다.
/* 강제 완료 */ boollush_work(struct work_struct *work); boollush_delayed_work(struct Delayed_work *dwork); /* 작업 실행 취소 */ bool cancel_work_sync(struct work_struct *work); bool cancel_delayed_work(struct Delayed_work *dwork); bool cancel_delayed_work_sync(struct Delayed_work *dwork); /* 큐 삭제 */ void destroy_workqueue(struct workqueue_struct *wq);

근로자가 업무를 수행하는 방법

이제 우리는 API에 익숙해졌으므로 API가 어떻게 작동하고 관리되는지 더 자세히 이해해 보겠습니다.
각 풀에는 작업을 처리하는 작업자 집합이 있습니다. 또한, 근로자 수는 현재 상황에 맞춰 동적으로 변화합니다.
우리가 이미 알아낸 것처럼 워커는 커널 컨텍스트에서 작업을 수행하는 스레드입니다. 작업자는 연결된 작업자 풀에서 순서대로 이를 검색하며, 이미 알고 있듯이 작업자는 다른 소스 대기열에 속할 수 있습니다.

작업자는 조건부로 세 가지 논리적 상태, 즉 유휴 상태, 실행 중, 관리 상태일 수 있습니다.
작업자는 다음과 같이 할 수 있습니다. 가만히 서 있다그리고 아무것도 하지 마세요. 예를 들어 모든 작업이 이미 실행 중인 경우입니다. 워커가 이 상태에 들어가면 휴면 상태가 되며 깨어날 때까지 실행되지 않습니다.
풀 관리가 필요하지 않고 예약된 작업 목록이 비어 있지 않으면 작업자가 해당 작업을 실행하기 시작합니다. 우리는 일반적으로 그러한 근로자를 부를 것입니다 달리기.
필요한 경우 작업자가 역할을 맡습니다. 관리자수영장. 풀에는 관리 작업자가 한 명만 있거나 작업자가 전혀 없을 수 있습니다. 그 임무는 풀당 최적의 작업자 수를 유지하는 것입니다. 그는 어떻게 합니까? 첫째, 장기간 유휴 상태인 작업자가 삭제됩니다. 둘째, 세 가지 조건이 동시에 충족되면 새로운 작업자가 생성됩니다.

  • 아직 완료해야 할 작업이 있습니다(풀에서 작동).
  • 유휴 근로자 없음
  • 일하는 근로자가 없습니다 (즉, 활동적이고 잠을 자지 않습니다)
그러나 마지막 조건에는 고유한 뉘앙스가 있습니다. 풀 대기열이 연결되지 않은 경우 실행 중인 작업자는 고려되지 않습니다. 작업자의 경우 이 조건은 항상 true입니다. 작업자가 연결된 작업에서 작업을 실행하는 경우에도 마찬가지입니다. WQ_CPU_집중, 대기열. 더욱이 묶인 대기열의 경우 작업자는 공통 풀(위 그림의 각 코어에 대해 2개 중 하나)의 작업으로 작업하므로 일부는 작업 중인 것으로 간주되고 일부는 작동하지 않는 것으로 나타났습니다. 또한 다음에서 작업을 수행합니다. WQ_CPU_집중대기열은 즉시 시작되지 않을 수 있지만 대기열 자체는 다른 작업의 실행을 방해하지 않습니다. 이제 이 플래그를 왜 그렇게 부르는지, 작업을 완료하는 데 오랜 시간이 걸릴 것으로 예상할 때 사용되는 이유가 분명해졌습니다.

작업 작업자에 대한 회계는 기본 Linux 커널 스케줄러에서 직접 수행됩니다. 이 제어 메커니즘은 최적의 동시성 수준을 보장하여 작업 대기열이 너무 많은 작업자를 생성하는 것을 방지할 뿐만 아니라 작업이 불필요하게 너무 오랫동안 기다리지 않도록 합니다.

관심 있는 분들은 커널의 작업자 함수(worker_thread())를 살펴보세요.

설명된 모든 기능과 구조는 파일에서 더 자세히 확인할 수 있습니다. include/linux/workqueue.h, 커널/workqueue.c그리고 커널/workqueue_internal.h. workqueue에 대한 문서도 있습니다. 문서/workqueue.txt.

작업 대기열 메커니즘이 지연된 인터럽트 처리에만 사용되는 것이 아니라 커널에서 사용된다는 점도 주목할 가치가 있습니다(비록 이는 매우 일반적인 시나리오임에도 불구하고).

따라서 우리는 멀티태스킹의 특별한 형태인 태스크릿 및 작업 대기열과 같은 Linux 커널의 지연된 인터럽트 처리 메커니즘을 살펴보았습니다. Jonathan Corbet, Greg Kroah-Hartman, Alessandro Rubini가 쓴 "Linux Device Drivers" 책에서 인터럽트, 태스크릿 및 작업 대기열에 대해 읽을 수 있지만 거기에 있는 정보는 때때로 오래된 것일 수도 있습니다.