สคริปต์ทุบตีดำเนินการร่วมกันไม่ได้ฆ่ากระบวนการพื้นหลัง


0

ฉันมีเชลล์สคริปต์จำนวนหนึ่งที่ทำงานคล้ายกับคำถามนี้มาก แต่ละสคริปต์ใช้งานแบ็คกราวนด์ไม่กี่ครั้งจดจำการ PID ด้วย$!ทำการทดสอบบางอย่างแล้วฆ่ากระบวนการพื้นหลัง

ปัญหาของฉันคือฉันต้องการเรียกใช้สคริปต์ประเภทนี้จำนวนมาก หากฉันเรียกใช้ด้วยตนเองทีละคนพวกเขาทำงานได้ดี: ps -aแสดงว่ากระบวนการพื้นหลังถูกฆ่าอย่างเหมาะสม

$ ./test_1.sh
$ ./test_2.sh

อย่างไรก็ตามถ้าฉันใช้ทั้งสองในหนึ่งคำสั่งเช่นนั้น:

$ ./test_1.sh; ./test_2.sh

กระบวนการพื้นหลังเริ่มต้นโดยtest_1.shล้มเหลวที่จะตายตามเวลาtest_2.shเริ่มต้น สิ่งนี้ทำให้พอร์ตเชื่อมโยงกันซึ่งtest_2.shจำเป็นต้องเชื่อมโยง ดังนั้นแม้ว่าtest_1.shปัญหาที่ถูกต้องkillคำสั่งเกิดปัญหาถ้ามันดำเนินการทันทีหลังจากที่test_2.shtest_1.sh

หากฉันแทรกการหน่วงเวลาระหว่างสคริปต์ไม่มีปัญหา:

$ ./test_1.sh; sleep 1; ./test_2.sh

จากนั้นสันนิษฐานว่ามีความล่าช้าระหว่างเมื่อkillมีการออกและเมื่อกระบวนการตายจริงและปล่อยพอร์ต

คำถามของฉันคือ:

  1. เกิดอะไรขึ้น? แพลตฟอร์มนี้เฉพาะเจาะจงหรือไม่ ฉันใช้ Mac OS X แต่สิ่งนี้ดูเหมือนจะไม่เป็นปัญหาสำหรับคนที่เขียนสคริปต์บน Linux มาก่อน
  2. มีวิธีที่ดีกว่าเพื่อให้แน่ใจว่ากระบวนการเบื้องหลังถูกฆ่าโดยไม่ใช้sleepระหว่างสคริปต์หรือไม่


เพื่อความสมบูรณ์นี่คือลักษณะของสคริปต์ทดสอบตัวใดตัวหนึ่ง:

#!/bin/sh

echo "starting up server 1(parent)..."
$JAVA siena.StartServer -port 7000 &
server1=$!
sleep 2

echo "starting up server 2(the first child)..."
$JAVA siena.StartServer -port 2000 -master senp://:7000 > outputs/test.out2 &
server2=$!

echo "starting up server 3(the second child)..."
$JAVA siena.StartServer -port 3000 -master senp://:7000 > outputs/test.out2 &
server3=$!

sleep 5

kill $server1
kill $server2
kill $server3

1
คำสั่งkillส่งสัญญาณไปยังกระบวนการเท่านั้นมันไม่ได้ตรวจสอบจริงๆว่ากระบวนการนั้นถูกฆ่าแล้ว โดยปกติแล้ว a SIGTERMจะถูกส่งซึ่งกระบวนการสามารถเพิกเฉยได้ แม้ว่ามันจะสอดคล้องกับมันก็อาจยังคงทำความสะอาดบ้านก่อนที่มันจะยุติจริง วิธีที่เร็วกว่าคือการฆ่าด้วยสัญญาณSIGKILLอย่างไรก็ตามกระบวนการจะไม่มีโอกาสที่จะกำจัดบัฟเฟอร์เช่นและมันจะยังคงไม่เกิดขึ้นทันที ฉันคิดว่าวิธีที่ปลอดภัยกว่าคือการสำรวจ/proc/<PROCID>เส้นทางหากมีอยู่ในระบบของคุณ
Marcus Rickert

คำตอบ:


1

คุณต้องรอให้กระบวนการตาย โดยปกติแล้วควรรอระหว่าง SIGTERM และ SIGKILL

ถือว่าเป็นมารยาทที่หยาบคาย (และในความเห็นของฉันค่อนข้างไม่เป็นมืออาชีพ) ต่อกระบวนการ SIGKILL โดยไม่ต้องขอให้ปิดเครื่องก่อน ไม่เพียง แต่สามารถสร้างความไม่สอดคล้องกันเท่านั้น แต่ยังซ่อนขั้นตอนการปิดระบบที่ผิดพลาด (โปรแกรมที่ไม่สามารถปิดในเวลาที่กำหนดเมื่อมีการร้องขอ)

ฉันจะใช้สิ่งที่ชอบ:

# Launch your processes...
DEADLINE=1   #seconds to wait
kill $server1 $server2 $server3
sleep $DEADLINE 
if kill -KILL $server1 $server2 $server3
then 
  echo "Warning: at least one process had not finished in $DEADLINE seconds" >&2
  sleep 1   ## Wait for these just-killed processes to actually die and free their ports
fi 

อีกวิธีคือการหาพอร์ตที่ว่างจากภายในตัวเซิร์ฟเวอร์เอง (การเชื่อมโยงโดยไม่มีพอร์ตและการสื่อสารภายนอกพอร์ตที่กำหนด) สิ่งนี้จะช่วยให้การทดสอบแบบขนาน คุณสามารถเขียนหมายเลขพอร์ตไปยังแฟ้มที่ระบุไว้ในบรรทัดคำสั่ง (แทนของพอร์ตคุณจะส่งชื่อไฟล์) จึงเปลี่ยน-port 7000เพื่อสิ่งที่ต้องการและจากนั้นรอให้ไฟล์นี้จะปรากฏแล้ว-port auto -port-file test-port.txt-master senp://:$(cat test-port.txt)

ความคิดอื่นก็คือการค้นหาโดยอัตโนมัติตามข้อมูลnetstat -ntlว่าพอร์ตที่คุณต้องการนั้นว่างหรือไม่ จากนั้นคุณสามารถเลือกที่จะรอหรือระบุชุดใหม่ของพอร์ตที่มีอยู่ สภาพการแข่งขันอาจเกิดขึ้นได้ดีในช่วงเวลาที่คุณเห็นพอร์ตว่างและช่วงเวลาที่คุณผูกโดยเฉพาะอย่างยิ่งหากอัลกอริทึมการจัดสรรของคุณถูกกำหนดและทำซ้ำได้ (เช่นการใช้พอร์ตแรกที่มีให้เริ่มต้นที่ 40000) การให้ระบบปฏิบัติการเลือกพอร์ตอิสระนั้นมีความแข็งแกร่งกว่ามาก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.