
질문
경로 이름에 디렉토리가 아닌 파일(파이프/소켓이라는 이름의 파일)이 있고 /tmp/foo
경로 이름에 디렉토리가 아닌 다른 디렉토리가 있다고 가정합니다 /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)
호출을 허용하는 *nix와 유사한 시스템이 있습니까? 호출이 성공하지만 동시에 성공하게 됩니까(연결 해제 순서를 변경하고 호출하는 프로세스에서 추상/숨기지 않기 때문인지 , 아니면 다른 기발한 경쟁 조건/버그를 통해서인지)?unlink(2)
rename(2)
link(2)
/tmp/foo
/tmp/bar
link(2)
현재의 이해
나는 Linux 및 몇 가지 BSD에 대한 맨페이지와 이러한 기능에 대한 POSIX 사양을 unlink(2)
읽었 습니다 . 그러나 나는 신중하게 고려해보면 이 문제에 대해 실제로 안심할 수 있는 내용이 포함되어 있지 않다고 생각합니다. 적어도 에서는rename(2)
link(2)
rename(2)
목적지이미 존재하는 경우 원자적으로 대체됩니다(OS 자체의 버그는 제쳐두고), 그러나 다른 것은 없습니다.
나는 보았다주장여러 개의 동시 실행은 rename(foo, qux)
원자적으로 이식 가능하게 하나의 이름 바꾸기를 제외하고 모두 실패하므로 ENOENT
유망합니다! 동일한 상황에서도 link(foo, bar)
실패 로 확장될 수 있는지 확실하지 않습니다 .ENOENT
선호하는 답변
link(2)
나는 이것이 "부정적인 것을 증명할 수 없는" 상황 중 하나라는 것을 알고 있습니다. 기껏해야 프로세스 2가 성공할 수 있도록 하는 *nix와 같은 시스템이 존재한다는 증거가 없다는 점만 주목할 수 있습니다 .
그래서 제가 찾고 있는 것은 가능한 많은 *nix 계열 시스템(적어도 Linux, OS X 및 다양한 BSD, 이상적으로는 Solaris 10과 같이 아직 일부 사용 중인 독점 시스템)을 다루는 답변입니다. 이러한 시스템과 제한된 문제 집합(원자적/잘 정렬된 파일 시스템 작업)에 대해 충분히 익숙하고 앞서 언급한 Mac과 같은 문제에 대해 알고 있다고 확신하는(현실적으로 가능한 한) 사람들로부터 제공됩니다. OS X - rename(2)
익숙한 플랫폼에 존재하는 경우 실제로는 원자적인 버그가 아닙니다. 그러면 이것이 내가 생각하는 방식대로 작동하고 신뢰할 수 있을 정도로 휴대성이 높다는 확신을 갖게 될 것입니다.
최종 메모
이것은 "X/Y 문제" 질문이 아닙니다. 다양한 잠금/IPC 메커니즘이나 이러한 특정 시스템 호출이 상호 작용하는 방식에 대한 불확실성을 해결하는 다른 방법을 참조하여 대답할 수 있는 근본적인 문제는 없습니다. 오늘날 실제로 사용되는 *nix 계열 시스템에서 예상대로 이식 가능하게 상호 작용하는 위의 시스템 호출에 의존할 수 있는지 알고 싶습니다.
답변1
등의 기준을 살펴보세요.POSIX이식성 보장을 위해. 실제로 대부분의 POSIX 호환 시스템은 사양과 약간의 차이가 있지만 일반적으로 사양에 제공된 보증을 신뢰할 수 있습니다. 대부분의 최신 유니스는 공식적으로 테스트되지 않은 경우에도 사양을 준수합니다. POSIX 모드에서 실행해야 할 수도 있습니다(예: bash를 사용하여 설정 하거나 Solaris에서 앞서 있는지 확인 POSIXLY_CORRECT=1
) ./usr/xpg4/bin
/bin
/usr/bin
PATH
단일 유닉스 v2(POSIX의 이전 확장)에 대해 다음과 같이 말합니다.link
:
이
link()
함수는 기존 파일에 대한 새 링크를 원자적으로 생성하고 파일의 링크 수가 1씩 증가합니다.
에 대한rename
:
링크 이름이 다음과 같은 경우새로운인수가 존재하면 제거되고오래된다음으로 이름이 변경됨새로운. 이 경우 new라는 링크는 이름 바꾸기 작업 전체에서 다른 프로세스에 계속 표시되며 다음 중 하나를 참조하는 파일을 참조합니다.새로운또는오래된수술이 시작되기 전.
POSIX는 대상이 존재하는 경우 대체가 원자적이어야 함을 명시적으로 명시합니다. 그러나 이름 변경 자체가 원자적이어야 한다는 점은 명시하지 않습니다. 즉, 두 가지 모두오래된그리고새로운문제의 파일을 참조하거나 둘 다 참조하지 않는 경우. 실제로 이러한 속성은 Unix 시스템, 적어도 로컬 파일 시스템에서는 적용됩니다.
또한 작업 순서가 보장됩니다. C에서는 ;
순차적 실행이 보장됩니다. sh에서 ;
/newline은 순차적 실행을 보장합니다(등등 &&
). 다른 프로그래밍 언어도 비슷한 보장을 제공합니다. 그래서
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에 대한 경험이 없습니다.