Pipe — bir processning chiqishini boshqa processning kirishiga uzatadigan kernel boshqaruvidagi byte oqimi. Pipe Unix va Linux tizimlarda processlararo aloqaning eng sodda mexanizmlaridan biri.
Anonymous pipe odatda related processlar, masalan parent va child orasida ishlaydi.
Shell’dagi | operatori bir nechta commandni pipelinega bog‘laydi.
Shell pipeline
Misol:
cat access.log | grep "500" | sort
Bu yerda:
catstdoutni pipe’ga yozadi.greppipe’dan stdin orqali o‘qiydi.grepnatijani keyingi pipe’ga yozadi.sortoqimni o‘qiydi.
Processlar bir vaqtda ishlashi mumkin.
Pipe yaratish
Operatsion tizim pipe() orqali ikki file descriptor beradi:
- read end;
- write end.
Parent fork() qilganda descriptorlar childga meros bo‘ladi.
Keraksiz uchlar yopiladi. Aks holda EOF kelmasligi mumkin.
Bir yo‘nalish
Klassik anonymous pipe bir yo‘nalishli.
Ikki tomonlama aloqa uchun:
ishlatiladi.
Ba’zi OS “pipe” atamasida ikki yo‘nalishli implementatsiya berishi mumkin, portable kod klassik modelga tayanadi.
Byte stream
Pipe xabar chegarasini saqlamaydi.
Writer:
"abc"
"def"
deb ikki marta yozsa, reader:
"abcdef"
yoki bo‘laklarda o‘qishi mumkin.
Protocol delimiter, fixed length yoki length prefix ishlatadi.
Atomic write
Ma’lum kichik hajmgacha pipe write atomik bo‘lishi kafolatlanadi. POSIXda bu chegara PIPE_BUF bilan bog‘liq.
Ikki writer kichik yozuv yuborsa, ularning baytlari aralashmasligi kerak.
Katta write qismlarga bo‘linib, boshqa writer bilan aralashishi mumkin.
Buffer
Pipe kernel bufferga ega.
Writer bufferga yozadi, reader o‘qib bo‘shatadi.
Buffer to‘lsa blocking writer kutadi.
Reader sekin bo‘lsa backpressure avtomatik yuz beradi.
Blocking read
Pipe bo‘sh, ammo write end ochiq bo‘lsa reader kutadi.
Barcha write descriptorlar yopilsa, reader EOF oladi.
Bir process keraksiz write endni ochiq qoldirsa, consumer cheksiz kutishi mumkin.
Broken pipe
Reader barcha read endlarni yopsa, writer pipe’ga yozolmaydi.
Unixda writer SIGPIPE signal olishi yoki EPIPE xatosi qaytishi mumkin.
Dastur signal va xatoni boshqaradi.
Exit status
Shell pipeline’da qaysi command exit statusi umumiy natija bo‘lishi shell siyosatiga bog‘liq.
Ko‘pincha oxirgi command statusi olinadi.
pipefail yoqilsa, oldingi command xatosi ham pipeline’ni failure qiladi.
Bu deployment va backup scriptlarda muhim.
Standard stream
Shell pipe odatda stdoutni keyingi stdin’ga bog‘laydi.
stderr alohida terminalga chiqadi.
stderrni ham pipe’ga berish uchun shell redirection ishlatiladi.
Stdout va stderr birlashtirilsa, yozuv tartibi buffering sabab o‘zgarishi mumkin.
Buffering
Dastur stdout terminalga ulanganida line-buffered, pipe’ga ulanganida block-buffered ishlashi mumkin.
Natijada pipeline’da output kech ko‘rinadi.
Dastur flush qilishi yoki unbuffered rejim ishlatishi mumkin.
tee
tee stdin’ni faylga va stdoutga bir vaqtda yozadi.
Misol:
command | tee output.log | next-command
Pipeline kuzatuvi va arxiv uchun qulay.
Subprocess
Dasturlash tilida child process stdin, stdout va stderr pipe orqali boshqariladi.
Parent:
- commandga input yuboradi;
- output oladi;
- error oladi;
- exit status kutadi.
Agar parent stdoutni o‘qimasdan child tugashini kutsa, pipe buffer to‘lib deadlock bo‘lishi mumkin.
Pipe deadlock
Child ko‘p stdout va stderr yozadi. Parent faqat stdoutni o‘qiydi.
stderr buffer to‘ladi, child bloklanadi. Parent child tugashini kutadi.
Ikki oqim parallel o‘qiladi yoki birlashtiriladi.
Non-blocking pipe
Descriptor non-blocking rejimga o‘tkazilishi mumkin.
Data yo‘q yoki buffer to‘la bo‘lsa EAGAIN qaytadi.
Event loop pipe’ni poll yoki epoll bilan kuzatadi.
Pipe va FIFO
Anonymous pipe filesystem nomiga ega emas va related processlar orqali descriptor merosiga tayanadi.
FIFO named pipe bo‘lib, mustaqil processlar path orqali ochadi.
Data xususiyati ikkalasida ham byte streamga o‘xshash.
Pipe va socket
- ikki yo‘nalish;
- bir nechta client;
- message mode;
- credential;
- file descriptor passing
imkoniyatlariga ega.
Pipe sodda producer-consumer oqimi uchun yengil.
Xavfsizlik
Pipe descriptorini faqat meros olgan yoki boshqa IPC orqali qabul qilgan process ishlata oladi.
Child processga keraksiz descriptorlarni yopmaslik ma’lumot sizishi yoki lifecycle muammosiga olib keladi.
close-on-exec flag yangi executable’ga descriptor o‘tishini cheklaydi.
Diagnostika
Pipe muammosida:
- read va write descriptor;
- qaysi process ochiq ushlab turibdi;
- EOF;
- buffer;
- blocked syscall;
- SIGPIPE;
- stdout/stderr;
- buffering;
- exit status;
- pipefail
tekshiriladi.
strace read va write qayerda bloklanganini ko‘rsatishi mumkin.
Pipeline performance
Pipeline processlari bir vaqtda ishlagani sababli umumiy tezlik eng sekin bosqich bilan cheklanadi.
Agar producer juda tez bo‘lsa, pipe buffer to‘ladi va producer bloklanadi. Bu tabiiy flow control hisoblanadi.
Katta data uchun keraksiz cat, format conversion va ko‘p process yaratish overhead qo‘shishi mumkin. Pipeline bosqichlari profiling orqali baholanadi.
Binary data
Pipe binary baytlarni ham tashiydi. Matn delimiteriga tayangan vosita nol bayt yoki encoding bilan noto‘g‘ri ishlashi mumkin. Binary protocol aniq length va format ishlatadi.
Pipeline yakunlanishi
Parent process barcha child processlarning exit statusini yig‘ishi kerak. Faqat output EOF bo‘lishi command muvaffaqiyatli tugaganini anglatmaydi; producer xato bilan tugagan bo‘lishi mumkin.
Bog‘liq tushunchalar
IPC, File descriptor, Standard input, Standard output, FIFO, Shell pipeline, Buffer, SIGPIPE, Subprocess