바삐 기다림

Busy waiting

컴퓨터 공학 및 소프트웨어 공학에서 비지 대기, 비지 루프 또는 회전은 프로세스가 키보드 입력 또는 잠금 사용 가능 여부 등 조건이 참인지 여부를 반복적으로 확인하는 기술입니다.스피닝은 임의의 시간 지연을 발생시키기 위해서도 사용할 수 있습니다.이는 특정 시간을 기다리는 방법이 없는 시스템에서 필요한 기술입니다.프로세서 속도는 컴퓨터마다 크게 다릅니다.특히 일부 프로세서는 현재의 워크로드에 [1]따라 동적으로 속도를 조정하도록 설계되어 있습니다.따라서 프로세서가 "do nothing" 루프를 실행하는 데 걸리는 시간을 결정하는 코드를 포함하거나 루프 코드가 실시간 클럭을 명시적으로 체크하지 않는 한 시간 지연 기술로 회전하면 다른 시스템에서 예측할 수 없거나 심지어 일관성이 없는 결과가 발생할 수 있습니다.

대부분의 경우 스피닝은 안티패턴으로 간주되어 [2]회피해야 합니다.이는 다른 태스크 실행에 사용할 수 있는 프로세서 시간이 불필요한 액티비티에 낭비되기 때문입니다.스피닝은 특정 상황에서 유효한 전략이 될 수 있습니다.특히 SMP 시스템 상에서 동작하도록 설계된 운영체제 내에서 스핀록을 구현하는 것이 가장 중요합니다.

예 C 코드

다음 C 코드 예는 글로벌 정수 i를 공유하는2개의 스레드를 나타내고 있습니다.첫 번째 스레드는 busy-waiting을 사용하여 i: 의 변화를 확인합니다.

#실패하다 <pthread.h> #실패하다 <datomic.h> #실패하다 <stdio.h> #실패하다 <stdlib.h> #실패하다 <리스트 없음.h>  /* i는 글로벌하기 때문에 모든 기능에 표시됩니다.그것은 특별한 것을 이용한다. * atomic_int 라고 입력합니다.이것에 의해, 아토믹 메모리에의 액세스가 가능합니다. */ atomic_int i = 0;  /* f1은 스핀록을 사용하여 i가 0에서 바뀔 때까지 기다립니다. */ 정적인 무효 *f1(무효 *p) {     인트 로컬_i;     /* i의 전류 값을 local_i에 원자적으로 로드하고 해당 값이 있는지 확인합니다. 0 * /     하는 동안에 ((로컬_i = atomic_load(&i)) == 0) {         /*는 아무것도 하지 않습니다.몇 번이고 계속 체크해 주세요*/     }      인쇄물("i 값이 %d로 변경되었습니다.\n", 로컬_i);     돌아가다 특수한 순서; }  정적인 무효 *f2(무효 *p) {     인트 로컬_i = 99;     수면.(10);   /* 10초간 sleep */     atomic_store(&i, 로컬_i);     인쇄물("t2가 i 값을 %d로 변경했습니다.\n", 로컬_i);     돌아가다 특수한 순서; }  인트 주된() {     인트 rc;     pthread_t t1, t2;      rc = pthread_create(&t1, 특수한 순서, f1, 특수한 순서);     한다면 (rc != 0) {         인쇄(하드, "pthread f1 실패\n");         돌아가다 EXIT_FAILURE;     }      rc = pthread_create(&t2, 특수한 순서, f2, 특수한 순서);     한다면 (rc != 0) {         인쇄(하드, "pthread f2 실패\n");         돌아가다 EXIT_FAILURE;     }      pthread_displays(읽기)(t1, 특수한 순서);     pthread_displays(읽기)(t2, 특수한 순서);     놓다("모든 pthread가 완료되었습니다.");     돌아가다 0; } 

이와 같은 활용 사례에서는 C11의 조건 변수 사용을 고려할 수 있습니다.

대체 수단

대부분의 운영 체제 및 스레드 라이브러리는 잠금 획득, 타이머 변경, I/O 가용성 또는 신호 등 이벤트 시 프로세스를 차단하는 다양한 시스템 호출을 제공합니다.이러한 콜을 사용하는 것으로, 일반적으로 가장 심플하고 효율적이며, 공정하고, 레이스가 없는 결과를 얻을 수 있습니다.단일 콜이 체크하고, 대기 중인 이벤트를 스케줄러에 통지하고, 필요에 따라 메모리 장벽을 삽입하여 요청된 I/O 작업을 수행한 후 복귀할 수 있습니다.발신자가 차단되어 있는 동안 다른 프로세스에서는 CPU를 사용할 수 있습니다.스케줄러에는 priority 상속 또는 기아 방지를 위한 기타 메커니즘을 구현하기 위해 필요한 정보가 제공됩니다.

비지 대기 자체는 지연 함수를 사용함으로써 낭비를 줄일 수 있습니다(예:sleep())는, 대부분의 operating system에 있습니다.그러면 스레드가 지정된 시간 동안 sleeve 상태가 되며 이 시간 동안 스레드는 CPU 시간을 낭비하지 않습니다.루프가 간단한 것을 체크하고 있는 경우, 루프는 대부분의 시간을 sleep 상태로 보내 CPU 시간을 거의 낭비하지 않습니다.

끝없는 프로그램(운영체제 등)에서는 다음 NASM 구문에 나타나 있듯이 무조건 점프를 사용하여 무한 비지 웨이트를 구현할 수 있습니다.CPU는 무조건위치로 이동합니다.이와 같은 비지 웨이트는 다음과 같이 대체할 수 있습니다.

sleep: 할 수 없다 jmp 수면. 

자세한 내용은 HLT(x86 지침)참조하십시오.

적절한 사용법

로우 레벨 프로그래밍에서는 비지 웨이트가 실제로 바람직할 수 있습니다.모든 하드웨어 디바이스, 특히 거의 접근하지 않는 디바이스에 대해 인터럽트 방식의 처리를 구현하는 것은 바람직하지 않을 수 있습니다.경우에 따라서는 하드웨어에 제어 데이터를 쓴 후 쓰기 조작으로 인해 디바이스 상태를 가져와야 할 수도 있습니다.이 상태는 쓰기 후 몇 번의 기계 사이클이 경과할 때까지 유효하지 않을 수 있습니다.프로그래머는 운영체제 지연함수를 호출할 수 있지만, 그렇게 하면 디바이스가 상태를 되돌리기를 기다리는 몇 클럭 사이클 동안 회전하는 데 걸리는 시간보다 더 오래 걸릴 수 있습니다.

「 」를 참조해 주세요.

레퍼런스

  1. ^ "Intel Turbo Boost Technology".
  2. ^ "Why the 'volatile' type class should not be used". Archived from the original on 2017-10-04. Retrieved 2013-06-10.

외부 링크