কীভাবে একই পাইপলাইনে একই ফাইলটি পড়া এবং লেখা সর্বদা "ব্যর্থ" হয়?


9

বলুন আমার কাছে নিম্নলিখিত স্ক্রিপ্ট রয়েছে:

#!/bin/bash
for i in $(seq 1000)
do
    cp /etc/passwd tmp
    cat tmp | head -1 | head -1 | head -1 > tmp  #this is the key line
    cat tmp
done

মূল লাইনে, আমি একই ফাইলটি পড়ি এবং লিখি tmpযা কখনও কখনও ব্যর্থ হয়।

(আমি এটি পড়ি জাতিগত অবস্থার কারণে কারণ পাইপলাইনের প্রক্রিয়াগুলি সমান্তরালভাবে সম্পাদন করা হয়, যা আমি বুঝতে পারি না কেন - প্রত্যেককে headপূর্ববর্তী থেকে ডেটা নেওয়া দরকার, তাই না? এটি আমার মূল প্রশ্ন নয়, তবে আপনি এটির উত্তরও দিতে পারেন))

আমি যখন স্ক্রিপ্টটি চালাব, এটি প্রায় 200 টি লাইন আউটপুট করে। এই স্ক্রিপ্টটি সর্বদা 0 লাইন আউটপুট করতে বাধ্য করার কোনও উপায় আছে (তাই I / O পুনর্নির্দেশটি tmpসর্বদা প্রথমে প্রস্তুত থাকে এবং তাই ডেটা সর্বদা নষ্ট হয়)? স্পষ্ট করে বলতে গেলে, আমি বোঝাতে চাইছি সিস্টেম সেটিংস পরিবর্তন করা, এই স্ক্রিপ্টটি নয়।

আপনার ধারণার জন্য ধন্যবাদ।

উত্তর:


2

গিলসের উত্তর দৌড়ের অবস্থা ব্যাখ্যা করে। আমি এই অংশটির উত্তর দিতে চলেছি:

এই স্ক্রিপ্টটি সর্বদা 0 লাইন আউটপুট করতে বাধ্য করার কোনও উপায় আছে (তাই আইএম / ও পুনর্নির্দেশটি ট্যাম্পে সর্বদা প্রথমে প্রস্তুত থাকে এবং তাই ডেটা সর্বদা নষ্ট হয়)? পরিষ্কার হওয়ার অর্থ, সিস্টেম সেটিংস পরিবর্তন করা changing

আইডিকে যদি এর জন্য কোনও সরঞ্জাম ইতিমধ্যে বিদ্যমান থাকে তবে কীভাবে এটি প্রয়োগ করা যেতে পারে সে সম্পর্কে আমার ধারণা রয়েছে। (তবে মনে রাখবেন এটি সর্বদা 0 লাইন হবে না , কেবল একটি দরকারী পরীক্ষক যা সহজেই এর মতো সহজ রেস এবং আরও কিছু জটিল রেস ধরবে @ @ গিলিসের মন্তব্য দেখুন )) এটি কোনও গ্যারান্টি দেয় না যে কোনও স্ক্রিপ্ট নিরাপদ ছিল , তবে সম্ভবত এআরএমের মতো দুর্বল-অর্ডারযুক্ত নন- x86 সিপিইউ সহ বিভিন্ন সিপিইউগুলিতে একাধিক-থ্রেড প্রোগ্রাম টেস্ট করার অনুরূপ, পরীক্ষার ক্ষেত্রে দরকারী সরঞ্জাম হয়ে উঠুন।

আপনি এটি হিসাবে চালানো চাই racechecker bash foo.sh

ট্রেসিং / আটকাচ্ছে সুবিধা যে একই সিস্টেম-কল ব্যবহার করুন strace -fএবং ltrace -fব্যবহার প্রত্যেক সন্তানের প্রক্রিয়া সংযুক্ত করতে। (লিনাক্স-এ, ptraceজিডিবি এবং অন্যান্য ডিবাগাররা ব্রেকপয়েন্ট, একক পদক্ষেপ এবং অন্য প্রক্রিয়ার মেমরি / রেজিস্টার সংশোধন করতে একই সিস্টেম কলটি ব্যবহার করে ))

ইনস্ট্রুমেন্ট openঅ্যান্ড openatসিস্টেম কল: যখন এই সরঞ্জামের অধীনে চলমান যে কোনও প্রক্রিয়া একটি open(2)সিস্টেম কল (বা openat) সাথে করে O_RDONLY, সম্ভবত 1/2 বা 1 সেকেন্ডের জন্য ঘুমান। অন্যান্য openসিস্টেম কলগুলিকে (বিশেষত যাদের সাথে রয়েছে O_TRUNC) দেরি না করে কার্যকর করতে দিন।

এটি লেখকের পক্ষে প্রায় প্রতিটি দৌড়ের দৌড় প্রতিযোগিতায় বিজয়ী হওয়া উচিত, যদি না সিস্টেমের চাপও বেশি ছিল না, বা এটি একটি জটিল রেস শর্ত ছিল যেখানে কাটা কাটা ঘটেনি অন্য কিছু পড়ার পরে until সুতরাং যেগুলির open()(এবং সম্ভবত read()এস বা লেখাগুলি) দেরি করা হয়েছে তার এলোমেলো প্রকরণটি এই সরঞ্জামটির সনাক্তকরণ শক্তি বাড়িয়ে তুলবে, তবে অবশ্যই একটি বিলম্ব সিমুলেটারের সাথে অসীম সময়ের জন্য পরীক্ষা না করেই শেষ পর্যন্ত আপনি যে সমস্ত সম্ভাব্য পরিস্থিতিগুলির মুখোমুখি হতে পারেন তা কাভার করবে eventually আসল বিশ্ব, আপনি নিশ্চিত হতে পারবেন না যে আপনার স্ক্রিপ্টগুলি রেস থেকে মুক্ত আছে যদি না আপনি সেগুলি মনোযোগ সহকারে পড়েন এবং প্রমাণ করেন যে তারা তা নয়।


openফাইলগুলির জন্য শ্বেত তালিকাতে (বিলম্ব না করা ) সম্ভবত আপনার এটির প্রয়োজন হবে /usr/binএবং /usr/libপ্রক্রিয়া-সূচনাটি চিরকালের জন্য লাগে না। (রানটাইম ডায়নামিক লিঙ্কিংয়ের open()একাধিক ফাইল থাকতে হবে (দেখুন strace -eopen /bin/trueবা /bin/lsকোনও সময় দেখুন), যদিও প্যারেন্ট শেল নিজেই কাটা কাটা করছেন, তবে তা ঠিক হবে But তবে এই সরঞ্জামটির জন্য স্ক্রিপ্টগুলি অযৌক্তিকভাবে ধীর না করা ভাল হবে)।

বা প্রতিটি ফাইলকে শ্বেতলিস্টে তালিকাবদ্ধ করতে কলিং প্রক্রিয়াটির প্রথম স্থানে কাটা করার অনুমতি নেই। উদাহরণস্বরূপ, ট্রেসিং প্রক্রিয়াটি কোনও ফাইলটি access(2)চেয়েছিল এমন প্রক্রিয়াটি স্থগিত করার আগে একটি সিস্টেম কল করতে পারে open()


racecheckerনিজেই সি তে লিখতে হবে, শেল নয়, তবে সম্ভবত straceকোডটি একটি সূচনা পয়েন্ট হিসাবে ব্যবহার করতে পারে এবং প্রয়োগ করতে খুব বেশি কাজ নাও লাগতে পারে।

আপনি সম্ভবত FUSE ফাইল সিস্টেমের সাথে একই কার্যকারিতাটি পেতে পারেন । খাঁটি পাসথ্রু ফাইল সিস্টেমের সম্ভবত ফুয়েস উদাহরণ রয়েছে, যাতে আপনি এতে open()ফাংশনে চেক যোগ করতে পারেন যা এটি কেবলমাত্র পঠনযোগ্য খোলার জন্য ঘুমিয়ে দেয় তবে অবিলম্বে কাটা কাটা পড়তে দেয়।


রেস চেকারের জন্য আপনার ধারণাটি আসলে কাজ করে না। প্রথমত, সমস্যাটি রয়েছে যে টাইমআউটগুলি নির্ভরযোগ্য নয়: একদিন অন্য লোকটি আপনার প্রত্যাশার চেয়ে বেশি সময় নেবে (এটি নির্মাণ বা পরীক্ষার স্ক্রিপ্টগুলির একটি দুর্দান্ত বিষয়, যা কিছুক্ষণের জন্য কাজ করে বলে মনে হয় এবং হার্ড-টু-ডিবাগ পদ্ধতিতে ব্যর্থ হয়) যখন কাজের চাপ প্রসারিত হয় এবং অনেকগুলি সমান্তরালে চালিত হয়)। কিন্তু এই বহুদূরে, যা খোলা তোমাদের বিলম্ব যোগ করতে যাচ্ছি? আকর্ষণীয় কিছু সনাক্ত করার জন্য, আপনাকে বিভিন্ন বিলম্বের ধরণ দিয়ে অনেকগুলি রান করতে হবে এবং তার ফলাফলগুলি তুলনা করতে হবে।
গিলস

@Gilles: রাইট, কোনো যুক্তিসঙ্গতভাবে-খানিক বিলম্বের নেই গ্যারান্টি আরোপ করা (ক প্রচন্ডভাবে লোড মেশিনে হিসাবে আপনি বাতলান) জাতি জয় হবে। এখানে ধারণাটি হ'ল আপনি এটি আপনার স্ক্রিপ্টটি কয়েকবার পরীক্ষা করতে ব্যবহার করেন, আপনি racecheckerসর্বদা ব্যবহার করেন না । এবং সম্ভবত আপনি খুব বেশি ভারী বোঝাই মেশিনে 10 মিনিটের মতো উচ্চতর সেট করতে চান এমন লোকদের সুবিধার্থে কনফিগারযোগ্য হওয়ার জন্য ওঠার জন্য পঠনযোগ্য ঘুমের সময়টি চাইবেন। বা এটি কম সেট করুন, যেমন দীর্ঘ বা অদক্ষ স্ক্রিপ্টগুলির জন্য 0.1 সেকেন্ডের মতো যা ফাইলগুলিকে প্রচুর পুনরায় খোলায় ।
পিটার

@ গিলস: বিভিন্ন বিলম্বের ধরণ সম্পর্কে দুর্দান্ত ধারণা, এটি আপনাকে ওপির ক্ষেত্রে "একই ধরণের পাইপলাইনের জিনিসগুলির মধ্যে" স্পষ্ট হওয়া উচিত (একবার আপনি শেলগুলি কীভাবে কাজ করেন তা জানার পরে) "চেয়ে আরও বেশি দৌড় পেতে পারে। কিন্তু "কোনটি খোলে?" শ্বেতলিস্ট বা প্রক্রিয়া শুরুতে বিলম্ব না করার জন্য অন্য কোনও উপায় সহ কেবল পঠনযোগ্য খোলা।
পিটার

আমি অনুমান করি যে আপনি ব্যাকগ্রাউন্ড কাজের সাথে আরও জটিল দৌড়গুলির কথা ভাবছেন যা অন্য কোনও প্রক্রিয়া শেষ না হওয়া অবধি কেটে যায় না? হ্যাঁ, এটি ধরার জন্য এলোমেলো পরিবর্তনের প্রয়োজন হতে পারে। অথবা প্রক্রিয়া গাছটি দেখুন এবং "শুরুর দিকে" আরও পড়তে দেরি করে, যাতে ক্রমগুলি স্বাভাবিক ক্রমকে উল্টানোর চেষ্টা করে। আপনি সরঞ্জামটিকে আরও এবং আরও পুনঃনির্মাণের সম্ভাবনাগুলি অনুকরণ করতে আরও জটিল করে তুলতে পারেন, তবে আপনি যদি মাল্টি-টাস্কিং করছেন তবে আপনার প্রোগ্রামগুলি সঠিকভাবে ডিজাইন করতে হবে। স্বয়ংক্রিয় পরীক্ষণ সহজ স্ক্রিপ্টগুলির জন্য কার্যকর হতে পারে যেখানে সম্ভাব্য সমস্যাগুলি আরও সীমাবদ্ধ।
পিটার কর্ডস

এটি মাল্টি-থ্রেড কোড, বিশেষত লকলেস অ্যালগরিদমগুলির পরীক্ষার মতোই অনুরূপ: এটি সঠিক হওয়ার কারণটি সম্পর্কে যৌক্তিক যুক্তি তেমনি পরীক্ষারও কারণ, আপনি সমস্ত পুনর্ব্যবহার তৈরি করতে কোনও নির্দিষ্ট মেশিনের পরীক্ষার উপর নির্ভর করতে পারবেন না কারণ আপনি যদি সমস্ত ফাঁকগুলি বন্ধ না করে থাকেন তবে সমস্যা হবেন। তবে ঠিক যেমন এআরএম বা পাওয়ারপিসির মতো দুর্বল-অর্ডারযুক্ত আর্কিটেকচারের পরীক্ষা করা যেমন অনুশীলনে একটি ভাল ধারণা, এমন একটি সিস্টেমের অধীনে একটি স্ক্রিপ্ট পরীক্ষা করা যা কৃত্রিমভাবে বিলম্বিত জিনিসগুলি কিছু ঘোড়দৌড়কে প্রকাশ করতে পারে , তাই এটি কোনও কিছুর চেয়ে ভাল। আপনি সবসময় বাগগুলি পরিচয় করিয়ে দিতে পারেন এটি ধরবে না!
পিটার

18

কেন রেসের শর্ত রয়েছে

পাইপের দুটি পক্ষই সমান্তরালভাবে কার্যকর হয়, একের পরের হয় না। এটি প্রদর্শনের জন্য খুব সহজ উপায় আছে: চালান

time sleep 1 | sleep 1

এটি এক নয়, দুটি নয়।

শেলটি দুটি শিশু প্রক্রিয়া শুরু করে এবং তাদের উভয়টি সম্পূর্ণ হওয়ার জন্য অপেক্ষা করে। এই দুই প্রক্রিয়ার সমান্তরাল চালানো যখন এটি শুধুমাত্র কারণে তাদের মধ্যে একজন অপরের সাথে সুসংগত হবে প্রয়োজন অপরের জন্য অপেক্ষা করতে। সিঙ্ক্রোনাইজেশনের সর্বাধিক সাধারণ বিষয় হ'ল ডান-হাতের ব্লকগুলি যখন তার স্ট্যান্ডার্ড ইনপুটটিতে ডেটা পড়ার জন্য অপেক্ষা করে এবং যখন বাম-হাত আরও ডেটা লেখেন তখন অবরুদ্ধ হয়ে যায়। কথোপকথনটিও ঘটতে পারে, যখন ডান হাতের তথ্য পড়তে ধীর হয় এবং তার লেখার অপারেশনটিতে বাম-হাতের ব্লকগুলি ডান-হাতটি আরও ডেটা না পড়া পর্যন্ত (পাইপটিতে নিজেই একটি বাফার থাকে, যার দ্বারা পরিচালিত হয়) কার্নেল, তবে এটির আকারটি একটি ছোট আকারের)।

সিঙ্ক্রোনাইজেশনের একটি বিন্দু পর্যবেক্ষণ করতে নিম্নলিখিত কমান্ডগুলি পর্যবেক্ষণ করুন ( sh -xপ্রতিটি কমান্ড এটি কার্যকরভাবে প্রিন্ট করে):

time sh -x -c '{ sleep 1; echo a; } | { cat; }'
time sh -x -c '{ echo a; sleep 1; } | { cat; }'
time sh -x -c '{ echo a; sleep 1; } | { sleep 1; cat; }'
time sh -x -c '{ sleep 2; echo a; } | { cat; sleep 1; }'

আপনি যা পর্যবেক্ষণ করছেন তাতে স্বাচ্ছন্দ্য না হওয়া অবধি পরিবর্তনের সাথে খেলুন।

যৌগিক কমান্ড দেওয়া হয়েছে

cat tmp | head -1 > tmp

বাম হাতের প্রক্রিয়াটি নিম্নলিখিতগুলি করে (আমি কেবলমাত্র আমার পদক্ষেপের সাথে সম্পর্কিত পদক্ষেপগুলি তালিকাভুক্ত করেছি):

  1. catযুক্তি দিয়ে বাহ্যিক প্রোগ্রামটি কার্যকর করুন tmp
  2. tmpপড়ার জন্য উন্মুক্ত ।
  3. এটি ফাইলের শেষে পৌঁছায়নি, ফাইলটি থেকে একটি অংশ পড়ুন এবং এটি স্ট্যান্ডার্ড আউটপুটে লিখুন।

ডান হাতের প্রক্রিয়াটি নিম্নলিখিতগুলি করে:

  1. tmpপ্রক্রিয়াতে ফাইল কেটে ফেলা, স্ট্যান্ডার্ড আউটপুট এ পুনঃনির্দেশ করুন ।
  2. headযুক্তি দিয়ে বাহ্যিক প্রোগ্রামটি কার্যকর করুন -1
  3. স্ট্যান্ডার্ড ইনপুট থেকে একটি লাইন পড়ুন এবং স্ট্যান্ডার্ড আউটপুট এ লিখুন।

সিঙ্ক্রোনাইজেশনের একমাত্র পয়েন্ট হ'ল ডান -3 বাম -3 এর জন্য একটি সম্পূর্ণ লাইন প্রক্রিয়াজাতকরণের জন্য অপেক্ষা করে। বাম -2 এবং ডান -1 এর মধ্যে কোনও সিঙ্ক্রোনাইজেশন নেই, সুতরাং এগুলি উভয় ক্রমেই ঘটতে পারে। তারা কী অর্ডারে ঘটবে তা অনুমানযোগ্য নয়: এটি সিপিইউ আর্কিটেকচার, শেল, কার্নেলের উপর নির্ভর করে, প্রসেসগুলি নির্ধারিত হওয়ার জন্য কোরের উপর নির্ভর করে, সেই সময়ের মধ্যে সিপিইউ কী বাধা দেয় ইত্যাদি উপর।

আচরণ কীভাবে পরিবর্তন করা যায়

সিস্টেম সেটিং পরিবর্তন করে আপনি আচরণটি পরিবর্তন করতে পারবেন না। কম্পিউটার আপনাকে যা করতে বলবে তা করে। আপনি এটিকে সমান্তরালভাবে ছাঁটাই tmpএবং পড়তে বলেছেন tmp, সুতরাং এটি দুটি জিনিসকে সমান্তরালে করে।

ঠিক আছে, এখানে একটি "সিস্টেম সেটিং" রয়েছে যা আপনি পরিবর্তন করতে পারেন: আপনি /bin/bashকোনও আলাদা প্রোগ্রাম দ্বারা প্রতিস্থাপন করতে পারেন যা বাশ নয়। আমি আশা করি এটি বলার অপেক্ষা রাখে না যে এটি কোনও ভাল ধারণা নয়।

আপনি যদি পাইপটির বাম-হাতের আগে কাটা কাটাটি চান তবে আপনাকে এটি পাইপলাইনের বাইরে রাখা দরকার, উদাহরণস্বরূপ:

{ cat tmp | head -1; } >tmp

অথবা

( exec >tmp; cat tmp | head -1 )

যদিও আপনি এটি চান তা আমার কোনও ধারণা নেই। আপনি যে ফাইলটি খালি থাকতে জানেন তা পড়ার কী দরকার?

বিপরীতভাবে, আপনি যদি catপড়া শেষ করে আউটপুট পুনর্নির্দেশটি (ট্র্যাঙ্কেশন সহ) সংঘটিত হতে চান তবে আপনাকে অবশ্যই মেমরিতে ডেটা পুরোপুরি বাফার করতে হবে, যেমন

line=$(cat tmp | head -1)
printf %s "$line" >tmp

বা অন্য কোনও ফাইলে লিখুন এবং তারপরে এটি স্থানান্তরিত করুন। এটি সাধারণত স্ক্রিপ্টগুলিতে কাজ করার শক্তিশালী উপায় এবং এতে সুবিধা রয়েছে যে ফাইলটি মূল নামের মাধ্যমে দৃশ্যমান হওয়ার পূর্বে পুরো লেখা রয়েছে।

cat tmp | head -1 >new && mv new tmp

Moreutils সংগ্রহে একটি প্রোগ্রাম যা ঠিক যে, বলা আছে অন্তর্ভুক্ত sponge

cat tmp | head -1 | sponge tmp

কীভাবে সমস্যাটি স্বয়ংক্রিয়ভাবে সনাক্ত করা যায়

যদি আপনার লক্ষ্যটি ছিল খারাপভাবে লিখিত স্ক্রিপ্টগুলি নিয়ে যাওয়া এবং সেগুলি কোথায় যায় সেগুলি স্বয়ংক্রিয়ভাবে নির্ধারণ করা, তবে দুঃখিত, জীবনটি এত সহজ নয়। রানটাইম বিশ্লেষণ নির্ভরযোগ্যভাবে সমস্যাটি খুঁজে পাবে না কারণ catকাটা কাটা হওয়ার আগে কখনও কখনও পড়া শেষ করে। স্থির বিশ্লেষণ নীতিগতভাবে এটি করতে পারে; আপনার প্রশ্নের সরলীকৃত উদাহরণ শেলচেক দ্বারা ধরা পড়েছে , তবে এটি আরও জটিল স্ক্রিপ্টে অনুরূপ সমস্যাটি নাও পেতে পারে।


স্ক্রিপ্টটি ভাল লেখা আছে কি না তা নির্ধারণ করা আমার লক্ষ্য ছিল। যদি স্ক্রিপ্টটি এভাবে ডেটা নষ্ট করে ফেলেছিল তবে আমি কেবল এটিই প্রতিবার এটি ধ্বংস করতে চেয়েছিলাম। এটি প্রায় অসম্ভব শুনে শুনে ভাল লাগবে না। আপনাকে ধন্যবাদ, আমি এখন সমস্যাটি কী তা জানি এবং একটি সমাধান চিন্তা করার চেষ্টা করব।
karlosss

@ কার্লোসস: হুম, আমি অবাক হয়েছি আপনি যদি একই সিস্টেম-কল ট্রেসিং / ইন্টারসেপিং স্টাফগুলি strace(যেমন লিনাক্স ptrace) হিসাবে openঅর্ধ সেকেন্ডের জন্য অল-রিডিং সিস্টেম কলগুলি (সমস্ত শিশু প্রসেসে) ঘুমানোর জন্য ব্যবহার করতে পারতেন , একটি কাটা, কাটা প্রায় সবসময় জিততে হবে।
পিটার

@ পিটারকর্ডস আমি এটির জন্য একটি নবজাতক, যদি আপনি এটি অর্জনের কোনও উপায় পরিচালনা করতে এবং উত্তর হিসাবে এটি লিখতে পারেন তবে আমি তা গ্রহণ করব।
karlosss

@ পিটারকর্ডস আপনি গ্যারান্টি দিতে পারবেন না যে কাটা বিলম্বের সাথে বিজয়ী হবে। এটি বেশিরভাগ সময় কাজ করবে তবে মাঝে মাঝে ভারী বোঝাই মেশিনে আপনার স্ক্রিপ্টটি কমবেশি রহস্যজনক উপায়ে ব্যর্থ হবে।
গিলস 'তাই খারাপ হওয়া বন্ধ করুন'

@ গিলস: আসুন আমার উত্তরের অধীনে এটি আলোচনা করুন।
পিটার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.