2010-07-06 2 views
4

최근 면접자가 버퍼 유형에 대해 질문했습니다. 어떤 유형의 버퍼가 있습니까? 사실이 질문은 시스템을 모니터링하기 위해 모든 시스템 호출을 로그 파일에 기록 할 것이라고 말했을 때 나타났습니다. 그는 파일에 대한 각각의 모든 호출을 작성하는 것이 천천히 진행될 것이라고 말했다. 그것을 방지하는 방법. 나는 버퍼를 사용할 것이라고 말했고 어떤 타입의 버퍼를 요구 했습니까? 어떤 사람이 제게 어떤 종류의 완충제를 설명해 주실 수 있습니까?버퍼 유형

+0

응용 프로그램에서 출력을 버퍼링하면 로그 파일이 덜 유용해질 수 있습니다. "시스템 모니터링"에 "고장 진단"이 포함되어 있으면 출력을 지연 시키면 더 어려워 질 수 있습니다. 그냥 생각. 인터뷰에서 유스 케이스에 대한 명확한 질문을하는 것이 도움이 될 수 있습니다. –

+0

@Heath 제안 해 주셔서 대단히 감사합니다. – mousey

+0

OS 내부 (시스템 호출 구현 자의 POV) 또는 응용 프로그램에서 로깅을 구현하는 것에 대한 질문이 있었습니까? –

답변

5

UNIX (및 다른 운영 체제 일 수도 있음)의 C에는 적어도 주어진 시나리오에서 두 개의 버퍼가 있습니다.

먼저 C 런타임 라이브러리에 기록 된 정보가 버퍼링되어 OS로 전달됩니다.

두 번째는 OS 자체에 있으며, 물리적으로 기본 미디어에 정보를 쓸 수있을 때까지 정보가 버퍼링됩니다.

예를 들어 많은 달 전에 기록 라이브러리를 작성하여 강제로 정보를 디스크에 기록하면 프로그램이 손상되거나 OS가 손상된 경우에도 정보가 기록됩니다.

시퀀스로 달성되었다

fflush (fh); fsync (fileno (fh)); 

이들 중 첫 번째는 실제로 정보가 디스크에 기록 된 제 것을 운영 체제에 C 런타임 버퍼로부터 계승 된 것을 보장. 이는 값 비싼 작업이므로 즉시 작성한 정보가 절대적으로 필요한 경우에만 수행해야합니다 (우리는 SUPER_ENORMOUS_IMPORTANT 로깅 수준에서만 수행했습니다).

솔직히 말하면, 당신의 면접관이 lot 정보를 쓰지 않는 한 왜 천천히 느냐고 완전히 확신 할 수 없습니다. 이미 존재하는 두 수준의 버퍼링은 아주 적절하게 수행되어야합니다. 만약 이라면, 메모리 오버플로에 메시지를 쓴 다른 레이어를 소개 한 다음 오버플로가 발생할 때 fprint 타입의 단일 호출로 전달할 수 있습니다.

그러나 함수 호출없이 수행하지 않는 한 fprint 유형 버퍼링이 이미 제공 한 것보다 훨씬 빠르다는 것을 알 수 없습니다.


이 질문은 커널 내부 버퍼링에 대해 실제로 있다는 의견에 명확히 다음은 기본적으로

, 당신은이 같은 빠르고, 효율적이고 실행 가능한 (실패 또는 리소스 부족하는 경향이되지 않음)되고 싶어 가능한 한 .

아마 가장 좋은 방법은 정적으로 할당되거나 동적으로 한 번 부팅 할 때 (동적 재 할당이 실패 할 가능성을 피하기 위해) 한 번 버퍼가 될 것입니다.

다른 사람들은 반지 (또는 원형) 버퍼를 제안했지만 다음과 같은 이유로 기술적으로는 그렇게하지 않을 것입니다. 고전 원형 버퍼를 사용한다는 것은 데이터를 쓸어 버릴 때 쓰는 것을 의미합니다. 2 개의 독립적 인 쓰기를 취하십시오. 예를 들어, 버퍼가있는 경우 :

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
|s|t|r|i|n|g| |t|o| |w|r|i|t|e|.| | | | | | |T|h|i|s| |i|s| |t|h|e| | 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
           ^  ^
           |   | 
        Buffer next --+   +-- Buffer start 

은 다음 "string to write." 다음 "This is the "를 작성해야합니다.

포인터 대신 next 포인터를 유지하고 버퍼에있는 바이트와 버퍼 크기가 더한 경우 버퍼에 기본 미디어에 물리적으로 기록하지 않고 추가하십시오.

버퍼 오버플로 경우에만 까다로운 일을 시작합니다.

당신이 취할 수있는 두 가지 방법 중 하나를

  • 어느 쪽이 약자로 플러시 버퍼, 다시 새 메시지를 처리하기위한 시작에 next 포인터를 설정; 또는
  • 메시지의 일부를 추가하여 버퍼를 채운 다음 플러시하고 나머지 메시지 처리를 위해 next 포인터를 다시 시작 부분으로 설정하십시오.

아마 어쨌든 버퍼에 비해 너무 큰 메시지를 고려해야한다는 점에서 두 번째 옵션을 선택하게됩니다. 기본적으로 효율적으로 물리적 쓰기의 수를 줄여 모든 크기의 메시지를 처리 ​​

initBuffer: 
    create buffer of size 10240 bytes. 
    set bufferEnd to end of buffer + 1 
    set bufferPointer to start of buffer 
    return 

addToBuffer (size, message): 
    while size != 0: 
     xfersz = minimum (size, bufferEnd - bufferPointer) 
     copy xfersz bytes from message to bufferPointer 
     message = message + xfersz 
     bufferPointer = bufferPointer + xfersz 
     size = size - xfersz 
     if bufferPointer == bufferEnd: 
      write buffer to underlying media 
      set bufferPointer to start of buffer 
     endif 
    endwhile 

: 내가 무슨 말

이 같은 것입니다. 물론 최적화가있을 것입니다. 메시지가 커널 공간에 복사되었을 수 있으므로 어쨌든 그것을 작성하려고한다면 버퍼에 복사하는 것이 거의 의미가 없습니다. 커널 복사본의 정보를 기본 미디어에 직접 쓰고 마지막 비트 만 버퍼로 전송할 수 있습니다 (저장해야하기 때문에).

또한 한 번 작성된 내용이 없으면 불완전한 버퍼를 기본 미디어로 플러시 할 수 있습니다. 그러면 커널 자체가 다운되는 기회에 정보가 누락 될 가능성이 줄어 듭니다.

는 제외 : 기술적으로,이 은 순환 버퍼의 일종의 추측하지만, 쓰기의 수, 그 때문에 최적화의 꼬리 포인터에 대한 필요성을 최소화하기 위해 처리하는 특별한 경우가 있습니다.

+0

+1입니다. 인터뷰에서이 질문을 받았다면 "stdio buffers"라고 말했을 것입니다. –

+0

상세한 expalanation을 가져 주셔서 대단히 감사합니다. – mousey

0

내게 떠오르는 것은 시간 기반 버퍼와 크기 기반입니다. 따라서 버퍼에있는 내용을 x 초/분/시간 또는 기타 시간에 한 번 쓸 수 있습니다. 또는 x 개의 로그 항목 또는 x 바이트의 로그 데이터가있을 때까지 기다렸다가 한 번에 모두 기록 할 수 있습니다. 이것은 log4net 및 log4J가 수행하는 방법 중 하나입니다.

2

제한된 공간 요구 사항을 갖고 있으며 유닉스 dmesg 시설에서 가장 잘 알려져있는 ring buffers도 있습니다.

0

전반적으로 대기열이라고도하는 "선입 선출 (First-In-First-Out)"(FIFO) 버퍼가 있습니다. "Latest * -In-First-Out"(LIFO) 버퍼 (스택이라고도 함)가 있습니다.

FIFO를 구현하려면 일반적으로 고정 크기 바이트 배열이 할당 된 경우에 사용되는 circular buffers이 있습니다. 예를 들어, 키보드 또는 직렬 I/O 장치 드라이버가이 방법을 사용할 수 있습니다. 이것은 동적으로 메모리를 할당 할 수없는 경우 (예를 들어, OS의 가상 메모리 (VM) 서브 시스템의 동작에 필요한 드라이버에서) 메모리를 할당 할 수없는 경우에 사용되는 일반적인 유형의 버퍼이다.

동적 메모리를 사용할 수있는 경우 FIFO는 여러 가지 방법, 특히 링크 된 목록에서 파생 된 데이터 구조로 구현할 수 있습니다.

또한, priority queues을 구현하는 이항 힙이 FIFO 버퍼 구현에 사용될 수있다.

FIFO 또는 LIFO 버퍼가없는 특별한 경우는 TCP 세그먼트 리 어셈블리 버퍼입니다. 이것들은 아직 도착하지 않은 중간 세그먼트의 수령이 보류 될 때까지 비 순차적으로 수신 된 세그먼트 ("미래로부터")를 보유 할 수 있습니다. 하지 최신

*이 내 약어는 더 나은,하지만 대부분은 LIFO "마지막에서 먼저 아웃"을 부를 것이다.

+0

귀하의 약어가 더 나아지지 않습니다. 기술 용어의 잘 정립 된 의미를 유지하는 것이 좋습니다. 자신의 의미 나 철자를 고안하면 혼란이 생길 ​​수 있으며 심지어는 무능력의 징조로 보일 수도 있습니다. – Secure

+0

물론, 약어가 제한되어 있기 때문에 이미 존재하는 두문자어와 충돌하는 개념을 발명하는 데는 잘못된 점이 없습니다. 기존 개념의 재정의를 피하십시오. – Secure

+0

와우, 내 downvote와 코멘트에 의해 개인적으로 모욕감을 느끼고, 내 모든 오래된 답변을 읽고 그 중 많은 것을 downvoting하는 것 같습니다. 이렇게되어 미안합니다. 그러나 이러한 반응은 미래에 downvotes를받는 확실한 방법입니다. ** 실제로 이유를 설명하지 않고 말입니다. – Secure

0

내가 틀렸다면 정정하십시오. 로그에 mmap 'd 파일을 사용하지 않으면 작은 write syscalls의 오버 헤드와 응용 프로그램 (OS가 아닌)이 손상되었을 때 데이터가 손실 될 수 있습니다. 나에게 성능과 안정성 사이의 이상적인 균형처럼 보입니다.