ডেডলকস এবং লাইভলকস - আমি কীভাবে বাস্তব বিশ্বে সমান্তরালতা এড়াতে পারি?

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

লাইভলকগুলি ঘটে যখন আমরা অ্যাসিক্রোনাস লকিংয়ের মাধ্যমে ডেডলকগুলি এড়াতে চেষ্টা করি, যেখানে একাধিক থ্রেড একই নির্দিষ্ট লক (গুলি) লকের জন্য প্রতিযোগিতা করে এবং এগিয়ে যায়; ক্ষুধার কারণ। অডিয়েন্স লক, যা একটি অচলাবস্থা এড়ানোর কৌশল, কীভাবে লাইভলক সৃষ্টি করতে পারে তা বুঝতে নীচে দেখুন

এখানে ডেডলকগুলির জন্য কিছু তাত্ত্বিক সমাধান রয়েছে এবং এর মধ্যে একটি (দ্বিতীয়) লাইভলকের মূল কারণ

তাত্ত্বিক পন্থা

লক ব্যবহার করবেন না

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

লক অবরুদ্ধ করবেন না কোনও থ্রেড যদি কোনও লক অর্জন করতে ব্যর্থ হয় তবে পরে আবার চেষ্টা করার জন্য এটি পূর্বে অর্জিত লকগুলি ছেড়ে দেওয়া উচিত

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

থ্রেডগুলিকে সর্বদা কঠোর ক্রমে অনুরোধ করা লকগুলিকে দেওয়া হোক

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

// সংকলনের সময় আমরা প্রথম যুক্তিতে লকটি নিই এবং তারপরে দ্বিতীয় পাবলিক শূন্য স্থানান্তর (অ্যাকাউন্ট এ, অ্যাকাউন্ট বি, দীর্ঘ অর্থ) nch সিঙ্ক্রোনাইজড (এ) nch সিঙ্ক্রোনাইজড (বি) {এএডিডি (পরিমাণ); বি বিয়োগ (পরিমাণ); }}}
// রানটাইমের সময় আমরা দেখতে পাই না যে কীভাবে আমাদের পদ্ধতিগুলিকে পাবলিক শূন্য রান () {নতুন থ্রেড (() -> this.transfer (এক্স, ওয়াই, 10000)) বলা হয়। শুরু (); নতুন থ্রেড (() -> this.transfer (Y, X, 10000)। শুরু (); } // এই রান () একটি অচলাবস্থা তৈরি করে // প্রথম থ্রেডটি এক্সে লক করে, ওয়াইয়ের জন্য অপেক্ষা করে // দ্বিতীয় থ্রেড ওয়াই লক করে এবং এক্স এর জন্য অপেক্ষা করে

আসল সমাধান

একটি সত্য শব্দের সমাধান পেতে আমরা লক অর্ডার এবং সময়সীমার লক পদ্ধতির সমন্বয় করতে পারি

ব্যবসায় নির্ধারিত লক অর্ডারিং

যার অ্যাকাউন্ট নম্বর বড় বা ছোট তার উপর নির্ভর করে আমরা A এবং B এর মধ্যে পার্থক্য করে আমাদের পদ্ধতির উন্নতি করতে পারি।

// রানটাইমের সময়, নিম্ন আইডি সহ ব্লকগুলিকে প্রথমে সর্বজনীন শূন্য স্থানান্তর (অ্যাকাউন্ট এ, অ্যাকাউন্ট বি, দীর্ঘ অর্থ) বিবেচনা করা হয় - চূড়ান্ত বিলিং প্রথম = এড
সিঙ্ক্রোনাইজড (প্রথম) nch সিঙ্ক্রোনাইজড (দ্বিতীয়) {first.add (পরিমাণ); দ্বিতীয় ছাড় (পরিমাণ); }}}
// রানটাইমের সময় আমরা দেখতে পাই না যে কীভাবে আমাদের পদ্ধতিগুলিকে পাবলিক শূন্য রান () {নতুন থ্রেড (() -> this.transfer (এক্স, ওয়াই, 10000)) বলা হয়। শুরু (); নতুন থ্রেড (() -> this.transfer (Y, X, 10000)। শুরু (); }

উদাহরণস্বরূপ, যদি X.id = 1111 এবং Y.id = 2222, ট্রান্সমিশন চালানোর জন্য লকিং অর্ডার (ওয়াই, এক্স, 10000) এবং সংক্রমণ (এক্স, ওয়াই, 10000) একই হবে। যদি X এর অ্যাকাউন্টের সংখ্যা Y এর চেয়ে কম থাকে, তবে উভয় থ্রেডই Y এর আগে এক্স লক করার চেষ্টা করবে এবং তাদের মধ্যে কেবল একটিই সফল হবে এবং Y শেষ করবে এবং অন্যান্য থ্রেড লকগুলি অর্জন করতে এবং চালিয়ে যাওয়ার আগে এক্স এবং Y আনলক করবে।

ব্যবসায়ের নির্ধারিত সময়সীমা অপেক্ষা করুন চেষ্টা লক / অ্যাসিঙ্ক লক অনুরোধগুলি

ব্যবসায়ের লক অর্ডার ব্যবহারের সমাধানটি কেবলমাত্র সহযোগী সম্পর্কের জন্য কাজ করে, যেখানে এক জায়গায় যুক্তি (...) নির্ধারণ করে যে সংস্থানগুলি কীভাবে সমন্বিত হয়।

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

// ধরুন অ্যাকাউন্ট # getLock () আমাদের অ্যাকাউন্টে লক দেয় (java.util.concurrent.locks.Lock)। // অ্যাকাউন্ট লকটি এনক্যাপসুলেট করতে পারে, লক সরবরাহ করতে পারে () / আনলক ()
সর্বজনীন দীর্ঘ getWait () // /// সর্বশেষ এন ট্রান্সফারগুলির জন্য স্থানান্তর সময়ের চলমান গড়কে ফিরে আসে + মিলিতে ছোট ছোট এলোমেলো লবণ যাতে লকের জন্য অপেক্ষা করা সমস্ত থ্রেড একই সাথে সক্রিয় না হয়। }
সর্বজনীন শূন্য স্থানান্তর (লকএফএফ, লকএস, ইনট পরিমাণ) {চূড়ান্ত বিলিং প্রথম = এআইডি
বুলিয়ান করা = মিথ্যা;
lock চেষ্টা করুন {চেষ্টা করুন {যদি (লকএফ.ট্রি লক (গেটওয়েট (), মিলিএসকোন্ডস)) {চেষ্টা করুন {যদি (লকস.ট্রি লক (getWait (), মিলিসিঙ্কেন্ডস) {সম্পন্ন = সত্য; }} অবশেষে {লকএস.আনলক (); }}} ক্যাচ (বাধাপ্রাপ্তি ই) }} অবশেষে {লকএফএফ.লনক (); !} যখন (! সম্পন্ন); }
// রানটাইমের সময় আমরা দেখতে পাই না যে কীভাবে আমাদের পদ্ধতিগুলিকে পাবলিক শূন্য রান () {নতুন থ্রেড (() -> this.transfer (এক্স, ওয়াই, 10000)) বলা হয়। শুরু (); নতুন থ্রেড (() -> this.transfer (Y, X, 10000)। শুরু (); }