질문
/tmp/foo
pathname 에 디렉토리가 아닌 파일(파일, 이름이 지정된 파이프/소켓 등)이 있고 pathname 에 디렉토리가 아닌 다른 디렉토리가 있다고 가정해 보겠습니다 /tmp/bar
. 그런 다음 두 개 이상의 프로세스가 동시에 실행되기 시작합니다.
프로세스 1의 기능은 다음과 같습니다.
unlink('/tmp/foo') /* or rename('/tmp/foo', '/tmp/removed') */
unlink('/tmp/bar') /* or rename('/tmp/bar', '/tmp/removed') */
프로세스 2 등은 다음 작업을 수행합니다.
link('/tmp/foo', '/tmp/bar')
내가 이해하는 바에 따르면, 프로세스 2는 성공할 수 없습니다. (아직 존재하는 동안 시도 link(2)
하는 경우에도 존재하므로 실패해야 하거나, 사라져서 실패해야 합니다.)/tmp/foo
/tmp/bar
EEXIST
/tmp/foo
ENOENT
unlink(2)
그러나 이 직관은 및/또는 시스템 호출이 연결 해제 효과에서 본질적으로 순차적이라는 가정에 의존하므로 rename(2)
내 이해에 대한 검증을 찾고 있습니다. 커널에서 두 개의 unlink(2)
AND/OR rename(2)
호출이 성공하도록 허용하는 *nix와 유사한 시스템이 있습니까? 그러나 둘 다 성공합니다 ( 프로세스 호출에서 AND를 추상화/숨기기보다는 AND 연결 해제 순서를 link(2)
변경 하거나 다른 이상한 경쟁 조건/버그를 통해)?/tmp/foo
/tmp/bar
link(2)
현재의 이해
나는 Linux와 일부 BSD의 unlink(2)
, rename(2)
, 및 매뉴얼 페이지와 이러한 기능에 대한 POSIX 사양을 읽었습니다. link(2)
하지만 곰곰히 생각해 보면 그 주제에 대해 안심할 만한 내용이 전혀 들어 있지 않은 것 같습니다. 적어도 rename(2)
우리는 약속합니다목적지이미 존재하는 경우 원자적으로 대체됩니다(운영 체제 자체의 결함을 제쳐두고), 그러나 다른 것은 없습니다.
나는 보았다주장하다여러 동시 실행은 rename(foo, qux)
하나의 이름 변경을 제외하고 모두 원자적으로 이식 가능하게 실패하므로 ENOENT
희망이 있습니다! 동일한 상황에서도 실패하도록 확장할 수 있는지 확실하지 않습니다 link(foo, bar)
.ENOENT
선호하는 답변
나는 이것이 "부정적인 것을 증명할 수 없는" 상황 중 하나라는 것을 알고 있습니다. 우리가 할 수 있는 최선은 link(2)
프로세스 2가 성공하도록 허용하는 *nix와 같은 시스템이 있다는 증거가 없다는 점에 유의하는 것입니다.
그래서 제가 찾고 있는 것은 가능한 한 많은 *nix 계열 시스템(적어도 Linux, OS 시스템 및 이 작은 범위의 문제(원자적/순서화된 파일 시스템 작업))을 다루는 답변입니다. 앞서 언급한 Mac OS X와 같은 문제에 대해 (가능한 한 많이) 알고 있다고 확신합니다. rename(2)
익숙한 플랫폼에 문제가 존재한다면 실제로는 원자적인 버그가 아닙니다. 이렇게 하면 내가 생각하는 대로 작동하고 신뢰할 수 있을 만큼 이식성이 높다는 확신을 갖게 될 것입니다.
최종 메모
이것은 "X/Y 문제" 질문이 아닙니다. 다양한 잠금/IPC 메커니즘이나 이러한 특정 시스템 호출이 어떻게 상호 작용하는지에 대한 불확실성을 해결하는 다른 방법을 소개함으로써 대답할 수 있는 근본적인 질문은 없습니다. 위의 시스템 호출을 사용하여 현재 실제로 사용되는 *nix 계열 시스템에서 예상대로 이식 가능한 상호 작용을 수행할 수 있는지 알고 싶습니다.
답변1
등의 기준을 살펴보세요.POSIX휴대성을 보장합니다. 실제로 대부분의 POSIX 호환 시스템은 사양에서 약간 벗어나지만 일반적으로 사양에 제공된 보증을 신뢰할 수 있습니다. 대부분의 최신 유니스는 공식적으로 테스트되지 않았더라도 이 사양을 준수합니다. bash 설정을 사용하거나 POSIXLY_CORRECT=1
Solaris에서 /usr/xpg4/bin
실행되는지 확인하는 등 POSIX 모드에서 실행해야 할 수도 있습니다 /bin
./usr/bin
PATH
단일 유닉스 v2(POSIX의 이전 확장)에는 다음과 같은 말이 있습니다.link
:
이
link()
기능은 기존 파일에 대한 새 링크를 자동으로 생성하고 파일의 링크 수가 1씩 증가합니다.
~에 대한rename
:
링크 이름이 있는 경우새로운매개변수가 존재하면 제거되며오래된다음으로 이름 바꾸기새로운. 이 경우 new라는 링크는 이름 바꾸기 작업 전체에서 다른 프로세스에 계속 표시되며 다음에서 참조됩니다.새로운또는오래된수술 시작 전.
POSIX는 대상이 존재하는 경우 해당 대체가 원자적이어야 함을 명시적으로 명시합니다. 그러나 이름 바꾸기 자체가 원자적이어야 한다고 명시하지는 않습니다. 즉, 두 가지가 동시에 발생하는 시점이 없습니다.오래된그리고새로운문제의 파일을 참조하거나 둘 다 사용할 수 없는 경우 참조하세요. 실제로 이러한 속성은 UNIX 시스템, 적어도 로컬 파일 시스템에서는 정확합니다.
또한 작업 순서가 보장됩니다. C에서는 ;
순차 실행이 보장됩니다. sh에서는 ;
/newline이 순차 실행(예: do &&
등)을 보장합니다. 그래서
unlink("/tmp/foo");
unlink("/tmp/bar");
/tmp/foo
존재했지만 존재하지 않았던 특정 시점이 없다는 것이 보장됩니다 /tmp/bar
( /tmp/bar
원래 존재했다고 가정). 따라서 동시 프로세스 실행이 link("/tmp/foo", "/tmp/bar")
성공할 수 없습니다.
원자성은 보장되지 않습니다.탄력. 원자성은 실시간 시스템에서 관찰 가능한 동작에 관한 것입니다. 파일 시스템의 맥락에서 복원력은 시스템이 충돌할 때 발생하는 상황을 나타냅니다. 많은 파일 시스템은 성능을 위해 탄력성을 희생하므로 실행이 unlink("foo"); unlink("bar");
중단되면(현재 디렉터리가 디스크 저장소에 있음) bar
삭제되어 foo
남겨질 수 있습니다.
일부 네트워크 파일 시스템은 다른 클라이언트에서 작업이 발생할 때 더 적은 보장을 제공합니다. 이전 NFS 구현은 이 문제로 악명 높았습니다. 현대적인 구현이 더 낫다고 생각하지만 현대적인 NFS에 대한 경험이 없습니다.