list :: খালি () বহু-থ্রেড আচরণ?


9

আমার কাছে একটি তালিকা রয়েছে যা থেকে আমি বিভিন্ন থ্রেডের উপাদানগুলি দখল করতে চাই। তালিকাটি খালি থাকাকালীন মুটেক্সকে রক্ষা করা লক করা এড়াতে, আমি empty()লক করার আগে যাচাই করি ।

কলটি list::empty()100% সময় সঠিক না হলে এটি ঠিক আছে । আমি কেবল ক্র্যাশ হওয়া বা একযোগে থাকা list::push()এবং list::pop()কলগুলি বিঘ্নিত হওয়া এড়াতে চাই ।

আমি কি ভিসি ++ ধরে নেওয়া নিরাপদ এবং জিএনসি জিসিসি কেবল কখনও কখনও empty()ভুল হয়ে যায় এবং এর চেয়ে খারাপ কিছুই না?

if(list.empty() == false){ // unprotected by mutex, okay if incorrect sometimes
    mutex.lock();
    if(list.empty() == false){ // check again while locked to be certain
         element = list.back();
         list.pop_back();
    }
    mutex.unlock();
}

1
না, আপনি এটি ধরে নিতে পারবেন না। আপনি উপাচার্যের মত একটি সহগামী ধারক ব্যবহার করতে পারে concurrent_queue
Panagiotis Kanavos

2
@ ফিউরিশ এটি একটি উত্তর হতে হবে। আমি যুক্ত করব যা std::list::sizeধ্রুবক সময় জটিলতার গ্যারান্টিযুক্ত রয়েছে, যার মূলত অর্থ হল আকার (নোডের সংখ্যা) একটি পৃথক ভেরিয়েবলে সংরক্ষণ করা দরকার; আসুন এটি কল size_std::list::emptyতারপরে সম্ভবত কিছু হিসাবে ফেরত দেয় size_ == 0এবং সমবর্তী পড়তে এবং লেখার size_ফলে ডেটা দৌড় হয়, তাই ইউবি।
ড্যানিয়েল ল্যাঙ্গার

@ ড্যানিয়েল্যাংর কীভাবে "ধ্রুবক সময়" পরিমাপ করা হয়? এটি কি একক ফাংশন কল বা সম্পূর্ণ প্রোগ্রামে রয়েছে?
কৌতূহলী

1
@ কুরিয়াসগুয়ে: ড্যানিয়েলল্যাঙ্গার আপনার তালিকার উত্তর "তালিকা নোডের সংখ্যা থেকে পৃথক" দিয়ে দিয়েছিল, এটি হে (1) এর সঠিক সংজ্ঞা, যার অর্থ প্রতিটি উপাদান কিছু সংখ্যক উপাদান নির্বিশেষে স্থির সময়ের চেয়ে কম সময়ে সম্পাদিত হয়। en.wikedia.org/wiki/Big_O_notation#Orders_of_common_funtions অন্য বিকল্প (সি ++ 11 অবধি) হবে লিনিয়ার = ও (এন) অর্থ, সেই আকারের উপাদানগুলি (লিঙ্কযুক্ত তালিকা) গণনা করতে হবে, যার জন্য আরও খারাপ হবে সম্মতি (কাউন্টারে অ অ্যাটমিক পড়ার / লেখার চেয়ে আরও স্পষ্ট ডেটা রেস)।
ফিরদা

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

উত্তর:


10

কলটি list::empty()100% সময় সঠিক না হলে এটি ঠিক আছে ।

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

আপনি যদি নিজের বিচক্ষণতার মূল্য দেন তবে আপনি পারফরম্যান্স হিট করবেন এবং চেক করার আগে মুটেক্সটিকে লক করে ফেলবেন। এটি বলেছিল, তালিকাটি আপনার জন্য সঠিক ধারকও নাও হতে পারে। আপনি যদি এটির সাথে ঠিক কী কাজ করছেন তা যদি আমাদের আমাদের বলতে পারেন তবে আমরা আরও ভাল ধারকটির পরামর্শ দিতে সক্ষম হতে পারি।


ব্যক্তিগত দৃষ্টিকোণ, কল list::empty()একটি রিড অ্যাকশন race-condition
Ngọc Khánh Nguyễn

3
@ এনগ্যাকখেনহুগুইন তারা যদি তালিকায় উপাদান যুক্ত করে থাকে তবে এটি একই সাথে একটি ডেটা রেসের কারণ হিসাবে আপনি একই সময়ে আকার লিখছেন এবং পড়ছেন।
নাথান অলিভার

6
এই টুইটটি বাতিল একটি জাতি শর্ত হয় read-writeবা write-write। আপনি যদি আমাকে
বিস্মিত না

1
@ এনগ্যাকখেনহুগুইন: কারণ লেখাগুলি বা পঠন উভয়ই পারমাণবিক বলে গ্যারান্টিযুক্ত নয়, সুতরাং একসাথে কার্যকর করা যেতে পারে, সুতরাং পাঠক পুরোপুরি ভুল কিছু পেতে পারে (ছেঁড়া পড়া বলা হয়)। কল্পনা করুন যে 0x00FF 0x0100 এ অল্প ইন্ডিয়ান 8-বিট এমসিইউতে লিখুন, কম 0xFF 0x00 লিখে আবার পাঠ্যটি ঠিক সেই শূন্য হয়ে যায়, উভয় বাইট পড়ে (থ্রেড লেখার গতি কমিয়ে দেয় বা স্থগিত করা হয়), উচ্চ বাইট 0x01 আপডেট করে লেখার অবিরত থাকে, তবে পঠন থ্রেডটি ইতিমধ্যে ভুল মান পেয়েছে (0x00FF বা 0x0100 নয় তবে অপ্রত্যাশিত 0x0000)।
ফিরদা

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

6

একটি পঠিত এবং একটি রচনা রয়েছে (সম্ভবত আমরা এর sizeসদস্যের কাছে std::list, যদি আমরা ধরে নিই যে এটির নামকরণ করা হয়েছে) যা একে অপরের সাথে রিগার্ডে সিঙ্ক্রোনাইজ হয় না । কল্পনা করুন যে একটি থ্রেড কল করে empty()(আপনার বাহিরে if()) অন্য থ্রেডটি অভ্যন্তরীণ প্রবেশ করে if()এবং সম্পাদন করে pop_back()। আপনি তখন একটি পরিবর্তনশীল পড়ছেন যা সম্ভবত, সংশোধন করা হচ্ছে। এটি অনির্ধারিত আচরণ।


2

কীভাবে জিনিসগুলি ভুল হতে পারে তার উদাহরণ হিসাবে:

যথেষ্ট পরিমাণে স্মার্ট সংকলক দেখতে পেল যা mutex.lock()সম্ভবত list.empty()রিটার্নের মান পরিবর্তন করতে পারে না এবং এইভাবে অভ্যন্তরীণ ifচেকটি পুরোপুরি এড়িয়ে যায় , অবশেষে pop_backএকটি তালিকার শীর্ষে যায় যার শেষ উপাদানটি প্রথমটির পরে মুছে ফেলা হয় if

কেন এটি করতে পারে? কোনও সিঙ্ক্রোনাইজেশন নেই list.empty(), সুতরাং যদি এটি একই সাথে পরিবর্তন করা হয় যা ডেটা রেস গঠন করে। স্ট্যান্ডার্ডটি বলেছে যে প্রোগ্রামগুলিতে ডেটা দৌড় থাকবে না, তাই সংকলকটি এটিকে মঞ্জুর করবে (অন্যথায় এটি প্রায় কোনও অপ্টিমাইজেশান সম্পাদন করতে পারে না)। অতএব এটি list.empty()অবিচ্ছিন্নভাবে একক থ্রেডেড দৃষ্টিভঙ্গি ধরে নিতে পারে এবং সিদ্ধান্ত নিতে পারে যে এটি অবশ্যই স্থির থাকবে।

এটি বেশ কয়েকটি অপটিমাইজেশন (বা হার্ডওয়্যার আচরণ )গুলির মধ্যে একটি যা আপনার কোডটি ভেঙে দিতে পারে।


বর্তমান a.load()+a.load()
সংকলকগুলি

1
পছন্দ করুন আপনি সেখানে সম্পূর্ণ ক্রম ধারাবাহিকতার জন্য অনুরোধ করেছেন, যাতে আপনি এটি পেয়ে যাবেন ...
ম্যাক্স ল্যাংফোফ

@MaxLanghof তোমার কি মনে হয় অপ্টিমাইজেশান কি a.load()*2সুস্পষ্ট? এমনকি a.load(rel)+b.load(rel)-a.load(rel)কোনওভাবেই অনুকূলিত হয় না। কিছুই হয় না। আপনি কেন লকগুলি (যা মূলত সিক সামঞ্জস্য রয়েছে) আরও বেশি অনুকূলিত হওয়ার আশা করছেন?
কৌতূহলী

@ কুরিয়াসগ্যুহেতু অ-পারমাণবিক প্রবেশাধিকারের মেমরি ক্রম (এখানে লকের আগে এবং পরে) এবং পরমাণুগুলি সম্পূর্ণ আলাদা? আমি লকটি আরও "আরও" অনুকূলিত হওয়ার আশা করি না, আমি প্রত্যাশা করি যে ক্রমগতভাবে সামঞ্জস্যপূর্ণ অ্যাক্সেসের চেয়ে আনসক্রোনাকৃত অ্যাক্সেসগুলি আরও অনুকূলিত করা হবে। লকটির উপস্থিতি আমার বক্তব্যের জন্য অপ্রাসঙ্গিক। এবং না, সংকলকটিকে অপ্টিমাইজ a.load() + a.load()করার অনুমতি নেই 2 * a.load()। আপনি আরও জানতে চাইলে এই বিষয়ে একটি প্রশ্ন জিজ্ঞাসা করুন।
ম্যাক্স ল্যাংফোফ

@ ম্যাক্সল্যাংহফ আপনি কী বলতে চাইছেন তা আমার কোনও ধারণা নেই। লকগুলি মূলত ক্রমানুসারে সামঞ্জস্যপূর্ণ। বাস্তবায়ন কেন কিছু থ্রেডিং আদিম (তালা) এবং কিছু অন্যের (পারমাণবিক) উপর অপ্টিমাইজেশন করার চেষ্টা করবে না? আপনি কি নন-অ্যাটমিক্স অ্যাক্সেসগুলি পারমাণবিক ব্যবহারের আশেপাশে অনুকূলিত হওয়ার আশা করেন?
কৌতূহলী
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.