명명된 파이프: 일부 실험으로 인해 혼란이 발생함

명명된 파이프: 일부 실험으로 인해 혼란이 발생함

다양한 기사와 질문을 읽었지만 매일 사용하는 내용으로 인해 여전히 혼란스럽고 그것이 얼마나 혼란스러운지 전혀 깨닫지 못했습니다. 저는 Linux에서 (이름이 지정된) 파이프를 실험하고 있습니다.

처음 시도는 간단합니다. 파이프 버퍼가 어떻게 작동하는지 알아보세요.

#1
mkfifo /tmp/mypipe
#2
echo "Hello World" >/tmp/mypipe
ctrl+c
#3
cat /tmp/mypipe

관찰하다echo: 데이터를 읽기 전에 종료 하면 cat파이프에 아무 것도 기록되지 않습니다( cat계속 실행되지만 파이프에서 아무것도 읽히지 않습니다). 를 입력 producent >named_pipe하고 종료할 때 producent파이프 버퍼 크기와 일치하는 데이터의 일부가 기록되고 named_pipe읽을 때까지 여기에 남아 있다고 가정합니다 consument(이제 작동 방식이 아니라는 것을 알고 있습니다). 그래서 제가 다음에 한 일은 다음과 같습니다.

2위consument파이프의 다른 쪽 끝에 연결해 보십시오 .

#1
mkfifo /tmp/mypipe
#2
echo "Hello World" >/tmp/mypipe
#3
cat /tmp/mypipe

관찰하다: 명령은 메시지를 cat표시 하고 두 프로세스가 모두 종료됩니다. "Hello World"여기서 흥미로운 점은 2단계에서는 ps -elf명령이 나타나지 않는다는 것입니다 echo. echo누군가가 파이프에서 데이터를 읽기를 기다리고 있는 것 같습니다. 이것이 첫 번째 시도에서 파이프에 아무 것도 인쇄되지 않는 이유입니다 .

세 번째 장소 파이프 명령이 "영원히" 실행되고 파이프에 계속 쓰고 무슨 일이 일어나는지 살펴보십시오.

#1
mkfifo /tmp/mypipe
#2
yes >/tmp/mypipe
#3
cat /tmp/mypipe

관찰하다: 이는 예상대로 작동하며 파이프에 전달된 내용을 cat인쇄합니다 . 하지만 대체를 yes사용해 보았습니다 . 이렇게 하면 명령이 종료될 때까지 아무 것도 인쇄되지 않습니다.cattail -ftailyes

4위 노력하는 것이 가장 큰 미스터리입니다.

# 1#
mkfifo /tmp/mypipe

# 2#
for i in $(seq 1 10000); do echo -n $i"|"> /tmp/mypipe; done

# 3#
for i in $(seq 1 10); do echo "${i}# Read:"; cat /tmp/mypipe && echo ""; done

그 후 3# 명령은 유사한 내용을 입력하기 시작합니다.

1# Read:
1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|
2# Read:
109|
3# Read:
110|
4# Read:
111|
5# Read:
112|
6# Read:
113|114|115|
7# Read:
116|
8# Read:
117|
9# Read:
118|119|120|121|122|123|124|125|126|127|128|129|130|131|132|133|134|135|136|137|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|158|159|160|161|162|163|164|165|166|167|168|169|170|171|172|173|174|175|176|177|178|179|180|181|182|183|184|185|186|187|188|189|190|191|192|193|194|195|196|197|198|199|200|201|202|203|204|205|206|207|208|209|210|211|212|213|214|215|216|217|218|219|220|221|222|223|224|225|226|227|228|229|230|231|232|233|234|235|236|237|238|239|240|241|242|243|244|245|246|247|248|249|250|251|252|253|254|255|256|257|258|259|260|261|262|263|264|265|266|267|268|269|270|271|272|273|274|275|276|277|278|279|280|281|282|283|284|285|286|287|288|289|290|291|292|293|294|295|
10# Read:
296|297|298|299|300|301|302|303|304|305|306|307|308|309|310|311|312|313|314|315|316|317|318|319|320|321|322|323|324|325|326|327|328|329|

질문:

첫 번째와 두 번째 시도:

  1. 이 특별한 경우 명명된 파이프는 |bash에서 알려진 클래식 파이프와 동일합니까?
  2. 생산자는 항상 소비자를 기다리나요? 그렇다면 파이프 버퍼의 목적은 무엇입니까? 이런 행위를 통신 차단이라고 하나요?
  3. Linux는 소비자가 파이프에 연결되어 통신할 수 있는 시기를 어떻게 알 수 있습니까? 시도해 보았지만 lsof named_pipe아무런 정보도 제공되지 않습니다. 이 정보는 어디에 저장되어 있나요? 또한 다음을 시도했는데 결과는 cat파이프에서 읽을 수 없다는 것입니다.

    #1
    mkfifo /tmp/mypipe
    #2
    echo 1 >/tmp/mypipe
    #3
    rm /tmp/mypipe
    #4
    mkfifo /tmp/mypipe
    #5
    cat /tmp/mypipe
    
  4. 입력 중: producent >/tmp/mypipe 입력과 동일 command |누군가가 한 명령을 다른 명령으로 파이프하고 싶지만 파이프 다음에 다른 명령을 입력하는 것을 잊어버린 상황을 의미합니까( ps이 경우에는 먼저 표시하지 않고 command)?

세 번째 시도:

  1. cat차이점은 무엇 입니까 ?tail -f

네 번째 시도:

  1. 여기서 무슨 일이 일어나고 있는 걸까요? 데이터 블록 크기 읽기가 부정확한 이유는 무엇입니까? 나는 출력이 다음과 같을 것으로 기대합니다 :

    1# 읽기: 1| 2# 읽기: 2|3# 읽기: 3|

추신: 다른 시작 명령 순서(먼저 읽은 후 쓰기)도 시도했지만 결과는 동일합니다.

PPS: 이것이 명확하길 바라지만, 생산자 = 파이프에 쓰는 프로세스입니다. 소비자 = 파이프에서 데이터를 읽는 프로세스입니다.

주로 C 스크립팅 지식이 약간 있는 사람에게 이 내용을 설명할 수 있습니까? 매우 감사합니다.

편집자 답변: Joe Sewell

  1. 삭제 확인
  2. 2.

내가 아는 한, 둘 다 병렬로 실행됩니다. 즉, 다음 두 가지는 동일하지 않습니다.

find | less

그리고

find > /tmp/file && less /tmp/file

다음 명령을 실행할 때 HDD가 작동하지 않고 less명령에 표시할 데이터가 충분할 때까지 정지되는 것처럼 보이는 것을 추가로 관찰했습니다.

find | less

shifg+g(파일 끝으로 이동 ) 을 클릭하면 less하드 드라이브가 즉시 작동을 시작하고 데이터 출력을 시작합니다. 이는 less명령에 표시할 데이터가 충분할 때 find더 이상 데이터를 생성하지 말라고 지시 한다는 의미입니까 ? 이것을 동기화라고 하나요? 파이프에 기록된 데이터의 양도 버퍼 크기와 일치합니까? 또한 클릭한 후 find상태( ps aux-stat 열)가 변경된 것을 확인했습니다.S+ to D+shift+gless

S    interruptible sleep (waiting for an event to complete)
D    uninterruptible sleep (usually IO)
+    is in the foreground process group.

┌─[wakatana@~] [63 files, 178Mb]
└──> ps aux | egrep -w 'less|find'
wakatana     6071  0.0  0.0  12736  1088 pts/5    S+   23:15   0:00 find
wakatana     6072  0.0  0.0   7940   928 pts/5    S+   23:15   0:00 less
wakatana     6183  0.0  0.0   7832   892 pts/6    S+   23:20   0:00 egrep --color=auto -w less|find
┌─[wakatana@~] [63 files, 178Mb]
└──> ps aux | egrep -w 'less|find'
wakatana     6071  0.0  0.0  12808  1304 pts/5    D+   23:15   0:00 find
wakatana     6072  0.0  0.0   9556  2508 pts/5    S+   23:15   0:00 less
wakatana     6193  0.0  0.0   7832   892 pts/6    S+   23:21   0:00 egrep --color=auto -w less|find
  • 누가 이 신호를 생산자에게 보냅니까? 그렇다면 소비자는 자신이 이미 제품이 있는 파이프라인(내 rm 파이프라인 예와 같은)에 연결되어 있다는 것을 어떻게 알 수 있습니까?

  • 삭제 확인

  • 삭제 확인

  • 나는 새로운 줄이 나를 혼란스럽게 한다고 생각하지 않습니다. 이전에 관찰한 내용(그리고 귀하의 확인: "예, 양쪽 끝이 서로를 기다립니다.")에 기초합니다. 나는 이것을 기대하고 있습니다 :

  • I. 첫 번째 루프의 첫 번째 반복은 파이프에 기록되며, 아무도 읽지 않으므로 여기서 기다립니다.

  • 2. 두 번째 루프가 실행되면 첫 번째 반복에서 첫 번째 루프에 의해 쓰여진 데이터가 읽혀지며 여기에는 아무것도 쓰여지지 않으므로 더 이상 읽을 수 없습니다.

  • 삼. 두 번째 루프는 첫 번째 루프가 다음 데이터를 쓸 때까지 기다리거나 (순서는 중요하지 않기 때문에) 첫 번째 루프는 두 번째 루프가 쓴 데이터를 읽을 때까지 기다립니다.

따라서 한 번의 쓰기가 한 번의 읽기에 해당할 것으로 예상합니다. 또한 루프가 실행되고 있지 않은지 확인하고 있었기 때문에 소비자가 내용을 읽지 않더라도 아무 것도 인쇄되지 않더라도 STDOUT에 무언가를 인쇄하는지 확인하기 위해 원래 명령 중 일부를 수정했습니다.

for i in $(seq 1 10000); do
  if [ $(( $i % 5 )) -eq 0 ]; then
    echo $i;
  else
    echo -n $i"|"> /tmp/mypipe;
  fi;
done

"작성 과정에서는 개행 문자가 전혀 전송되지 않으므로 독자는 '충분하다'는 말을 들을 때까지 읽기만 하면 됩니다."

  • 누가 소비자에게 충분하다고 말할 것인가?

"첫 번째 경우에는 fifo의 버퍼가 가득 찼을 수 있습니다."

  • 위에서 언급한 것처럼 통신이 차단된 경우 버퍼를 어떻게 채우나요?

"그래서 독자에게 달려갔습니다."

  • 무슨 뜻이에요? 죄송합니다. 제 영어 실력이 좋지 않습니다.

"통신을 비동기화하는 방법이 있지만..."

  • 이 경우 비동기와 동기화의 차이점이 무엇인지 간략하게 설명해 주실 수 있나요?

답변1

질문 목록에 번호별로 답변하려면 다음 단계를 따르세요.

  1. fifo라고도 알려진 명명된 파이프는 기본적으로 셸에서 생성된 명명되지 않은 파이프와 동일합니다. 가장 큰 차이점은 두 끝 사이의 쉘 버전 동기화가 직관적인 반면, 사용 중인 것으로 보이는 명명된 파이프에는 쉘이 수행하는 작업에 대한 지식이 필요하다는 것입니다.

  2. 예, 양측은 서로를 기다리고 있습니다. fifo의 목적은 한 프로세스의 출력을 다른 프로세스의 입력으로 전달하는 쉘 파이프의 목적과 동일합니다. 그들은아니요임시 파일. 나는 이것이 당신이 혼란스러워하는 곳이라고 생각합니다. 이와 같은 쉘 명령의 경우 cat somefile.txt | less,둘 다명령은 포크된 프로세스로 동시에 실행되며 파이프는 두 프로세스를 동기화하는 데 사용됩니다. 제 기억이 맞다면 C로 수정하면 되지만, 쉘 명령을 사용하면 그리 쉽지는 않죠.

  3. 프로세스는 파이프의 다른 쪽 끝이 연결될 때 신호를 받을 수 있지만 위에서 언급한 것처럼 전체 의도는 일반적으로 두 프로세스를 동기화 상태로 유지하는 것입니다. 작성자는 무언가를 보내고 쓰기 작업이 완료되었음을 알고 계속할 수 있습니다.

  4. bash그리고 tcsh그것은 당신이 "잊는" 것을 허용하지 않을 것입니다. 명령이 실행되지도 않습니다.

  5. tail -fstdin무엇이든 표시하려면 EOF를 얻을 때까지(이 경우) 전체 스트림을 읽어야 합니다 . 귀하의 실험에서는 엔딩이 발생하지 않았습니다. cat반면에 입력 처리는 즉시 시작될 수 있습니다.

  6. 쓰기 과정에서는 개행 문자가 전혀 전송되지 않으므로 독자는 "충분하다"는 말을 들을 때까지 읽기만 하면 됩니다. 첫 번째 경우에는 fifo의 버퍼가 가득 차서 판독기에 플러시되는 것일 수 있습니다. 후속 출력은 유사할 수 있으며 시스템 타이밍에 따라 달라질 수 있습니다.

여기서 또 다른 혼란스러운 문제를 다루겠습니다. 쉘은 리디렉션을 처리합니다.앞으로명령을 실행하십시오. 이는 FIFO의 다른 쪽 끝이 연결되기를 기다리고 있기 cat때문에 프로세스 목록에 표시되지 않음을 의미합니다.bash앞으로달리기 cat또는 작가와 관련된 모든 것. 마찬가지로 기록기가 연결될 때까지 읽기 명령을 실행하지 않습니다.

내 생각에 당신의 가장 큰 오해는 명명된 파이프가아니요임시 파일. 이름없는 통로도 아닙니다. 통신을 비동기식으로 만드는 방법이 있지만 다음에서 실제 임시 파일을 만드는 것이 /tmp더 나을 것 같습니다.하다두 프로세스가 동시에 실행되기를 원합니다.

답변2

find | less

shift+g(파일 끝으로 이동 ) 을 클릭하면 less하드 드라이브가 즉시 작동을 시작하고 데이터 출력을 시작합니다. 이는 less명령에 표시할 데이터가 충분할 때 find더 이상 데이터를 생성하지 말라고 지시 한다는 의미입니까 ?

캔트. 파이프는 read()s 및 s 에 사용할 수 있습니다 write(). less말하다find 아무것도 없다- 그러나 read()파이프를 소유한 시스템 커널은 연관된 프로세스가 있는 한 파이프를 플러시하지 않습니다. 이는 파이프 버퍼가 가득 차서 커널이 다른 버퍼를 허용하지 않기 때문에 계속할 find write()수 없을 때까지 계속됩니다 . 이것도 이렇다write()write()find막힌편집하다. 파이프 입력 끝으로 점프하면 less read()파이프에서 약간의 배수가 발생합니다.(모두)find- 이제 파이프 버퍼를 write()다시 사용할 수 있습니다. 디스크 검색을 재개하고 버퍼를 다시 채우거나 작업을 완료하려고 시도합니다.

같은 이유명명된 파이프- 이것은 완전히 똑같습니다 - 커널이 파이프의 양쪽 끝을 의사 파일과 연결하는 데 동의한다는 점을 제외하면협회- 파일 시스템 어딘가에 있습니다. 때를:

mkfifo pipe
echo > pipe &
rm pipe
mkfifo pipe
cat pipe

...당신은 함께 일하고 있습니다두 개의 다른관로. 첫 번째 unlink()는 ed에 의해 명명된 파일 시스템과 연결되어 있지만 rm여전히 echo파이프에서 기다리고 있습니다 read(). 하지만 이제 프로세스가 다른 쪽 끝을 찾을 가능성은 거의 없습니다. 실제로 기본적으로 명명된 파이프를 사용하면서 이 방법으로 익명으로 만들 수 있습니다. 이는 보안상의 이유로 일반적으로 가장 좋은 방법입니다.

노력하다:

   mkfifo pipe
   exec 3<>pipe 4<>pipe
   cat  <&3     >out.log &
   rm pipe
   echo read this, cat\! >&4

관련 정보