কেন অস্থিরতা বিদ্যমান?


222

volatileকীওয়ার্ডটি কী করে ? সি ++ এ এটি কোন সমস্যার সমাধান করে?

আমার ক্ষেত্রে, আমি কখনই জেনে বুঝেই এর প্রয়োজন হয়নি।



3
একটি উদ্ভট কৌশল আছে যা আপনার সংকলকটি সম্ভাব্য দৌড়ের পরিস্থিতি সনাক্ত করতে সক্ষম করে যা অস্থায়ী কীওয়ার্ডের উপর নির্ভর করে, আপনি এটি সম্পর্কে http://www.ddj.com/cpp/184403766 এ পড়তে পারেন ।
নেনো গাঞ্চেভ

volatileকার্যকরভাবে কখন ব্যবহার করা যায়, সুন্দর লেখনীর পদগুলিতে একসাথে রাখা যায় তার একটি উদাহরণ সহ এটি একটি দুর্দান্ত উত্স । লিঙ্ক: পাবলিকেশনস.
gbdirect.co.uk/c_book/chapter8/…

আমি এটি লক ফ্রি কোড / ডাবল
চেকড

আমার জন্য, কীওয়ার্ডের volatileচেয়ে বেশি দরকারী friend
acegs

উত্তর:


268

volatile আপনি যদি মেমোরির কোনও জায়গা থেকে পড়তে থাকেন তবে এটির প্রয়োজন আছে, বলুন, সম্পূর্ণ আলাদা প্রক্রিয়া / ডিভাইস / যা কিছু লিখতে পারে write

আমি সোজা সি-তে একটি মাল্টিপ্রসেসর সিস্টেমে ডুয়াল-পোর্ট র‌্যামের সাথে কাজ করতাম আমরা যখন অন্য লোকটি করা হয়েছিল তখন জানার জন্য একটি হার্ডওয়্যার একটি সেমফোর হিসাবে 16 বিট মান ব্যবহার করে। মূলত আমরা এটি করেছি:

void waitForSemaphore()
{
   volatile uint16_t* semPtr = WELL_KNOWN_SEM_ADDR;/*well known address to my semaphore*/
   while ((*semPtr) != IS_OK_FOR_ME_TO_PROCEED);
}

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


uint16_t* volatile semPtrএক্ষেত্রে পরিবর্তে লেখা থাকলে কী হবে ? এটি পয়েন্টারটিকে অস্থির হিসাবে চিহ্নিত করা উচিত (পরিবর্তিত মানের পরিবর্তে), যাতে পয়েন্টারে নিজেই পরীক্ষা করা হয়, যেমন, semPtr == SOME_ADDRঅনুকূলিত নাও হতে পারে। এটি আবার পাশাপাশি একটি অস্থির পয়েন্ট মান বোঝায়। কোন?
জিল

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

1
@Doug টি ভালো ব্যাখ্যা এই
machineaddict

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

1
@ কুরিয়াসগুয়ে না, কেবলমাত্র একবার অস্থিতিশীল কীওয়ার্ডটি প্রদর্শিত হওয়ার অর্থ এই নয় যে সমস্ত কিছু হঠাৎই অস্থির হয়ে ওঠে। আমি একটি দৃশ্যাবলী দিয়েছি যেখানে সংকলকটি সঠিক কাজ করে এবং একটি ফলাফল অর্জন করে যা প্রোগ্রামারটি ভুলভাবে প্রত্যাশা করে তার বিপরীত। ঠিক যেমন "মোস্ট ভেক্সিং পার্স" কম্পাইলার ত্রুটির চিহ্ন নয়, এখানেও নয় is
ইহানেয়

82

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


9
এটি কেবল এম্বেড থাকা সিস্টেমগুলির জন্যই বৈধ নয় সমস্ত ডিভাইস ড্রাইভার বিকাশের জন্য।
ম্লাদেন জানকোভিć

আমি একবার মাত্র 8 বিট আইএসএ বাসে এটির প্রয়োজন হয়েছিল যেখানে আপনি একই ঠিকানাটি দু'বার পড়েছিলেন - সংকলকটিতে একটি বাগ ছিল এবং এটিকে উপেক্ষা করা হয়েছিল (শুরুর দিকে জোরটেক সি ++)
মার্টিন বেকেট

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

69

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

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

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


5
আপনি যখন সংখ্যাসূচক ডেরিভেটিভগুলি গণনা করেন এটি x + h - x == h আপনি hh = x + h - x কে অস্থির হিসাবে সংজ্ঞায়িত করে যাতে সঠিক ব-দ্বীপটি গণনা করা যায় তা নিশ্চিত করাও দরকারী।
আলেকজান্দ্রি সি

5
+1, প্রকৃতপক্ষে আমার অভিজ্ঞতায় একটি মামলা ছিল যখন ভাসমান-পয়েন্ট গণনাগুলি ডিবাগ এবং রিলিজের বিভিন্ন ফলাফল তৈরি করে, তাই একটি কনফিগারেশনের জন্য লিখিত ইউনিট পরীক্ষা অন্যের জন্য ব্যর্থ হয়েছিল। আমরা ন্যায়বিচারের volatile doubleপরিবর্তে একটি ভাসমান-পয়েন্ট ভেরিয়েবল ঘোষণার মাধ্যমে এটি সমাধান করেছি double, যাতে এটি আরও গণনা চালিয়ে যাওয়ার আগে এফপিইউ নির্ভুলতা থেকে -৪-বিট (র‌্যাম) যথার্থ হয়ে যায় তা নিশ্চিত করা যায়। ভাসমান-পয়েন্ট ত্রুটির আরও অতিরঞ্জিত হওয়ার কারণে ফলাফলগুলি যথেষ্ট আলাদা ছিল।
সার্জ রোগাচ

"আধুনিক" এর আপনার সংজ্ঞাটি কিছুটা বন্ধ। কেবলমাত্র 32-বিট x86 কোড যা এসএসই / এসএসই 2 এড়ায় তা এর দ্বারা প্রভাবিত হয় এবং এটি 10 ​​বছর আগেও "আধুনিক" ছিল না। এমআইপিএস / এআরএম / পাওয়ার সকলের 64-বিট হার্ডওয়্যার রেজিস্টার রয়েছে এবং এসএসই 2 এর সাথে x86ও রয়েছে। সি ++ বাস্তবায়ন x86-64 সর্বদা এসএসই 2 ব্যবহার করে এবং সংকলকগুলির কাছে g++ -mfpmath=sseএটি 32-বিট x86- তেও ব্যবহার করার মতো বিকল্প রয়েছে। X87 ব্যবহার gcc -ffloat-storeকরার পরেও আপনি সর্বত্র রাউন্ডে জোর করার জন্য ব্যবহার করতে পারেন , বা আপনি x87 নির্ভুলতাটি 53-বিট ম্যান্টিসায় সেট করতে পারেন: randomascii.wordpress.com/2012/03/21/…
পিটার কর্ডেস 13

তবে এখনও উত্তম উত্তর, অপ্রচলিত x87 কোড-জেনের জন্য, আপনি যে volatileকোনও জায়গায় সুবিধা বঞ্চিত না করে কয়েকটি নির্দিষ্ট স্থানে জোর করে বল প্রয়োগ করতে পারেন ।
পিটার কর্ডেস

1
বা আমি অসম্পূর্ণ সাথে অসম্পূর্ণ বিভ্রান্ত না?
চিপস্টার

48

A থেকে "উদ্বায়ী একটি প্রতিশ্রুতি হিসাবে" ড্যান Saks দ্বারা নিবন্ধ:

(...) একটি উদ্বায়ী বস্তু এমন একটি যার মূল্য স্বতঃস্ফূর্তভাবে পরিবর্তিত হতে পারে। এটি হ'ল, যখন আপনি কোনও বস্তুকে অস্থির হিসাবে ঘোষণা করেন, আপনি কম্পাইলারকে বলছেন যে প্রোগ্রামে কোনও বিবৃতি এটি পরিবর্তন না করে সত্ত্বেও বস্তুটি রাষ্ট্রের পরিবর্তন হতে পারে ""

এখানে volatileকীওয়ার্ড সম্পর্কিত তাঁর তিনটি নিবন্ধের লিঙ্ক রয়েছে :


23

লক-ফ্রি ডেটা স্ট্রাকচার বাস্তবায়নের সময় আপনার অবশ্যই অস্থিতিশীল ব্যবহার করা উচিত। অন্যথায় সংকলকটি ভেরিয়েবলের অ্যাক্সেস অনুকূলিত করতে বিনামূল্যে, যা শব্দার্থকে পরিবর্তিত করবে।

এটি অন্য উপায়ে রাখতে, অস্থির এই সংস্থাপককে বলে যে এই ভেরিয়েবলটিতে অ্যাক্সেস করা অবশ্যই একটি শারীরিক মেমরি রিড / রাইটিং অপারেশনের সাথে সঙ্গতিপূর্ণ।

উদাহরণস্বরূপ, Win32 এপিআইতে এভাবেই ইন্টারলকডইনক্রিমেন্ট ঘোষিত হয়:

LONG __cdecl InterlockedIncrement(
  __inout  LONG volatile *Addend
);

ইন্টারলকডইনক্রিমেন্ট ব্যবহার করতে সক্ষম হতে আপনাকে একেবারে একটি পরিবর্তনশীল অস্থির ঘোষণা করার দরকার নেই।
কৌতূহলী

এই উত্তরটি এখন অপ্রচলিত যে সি ++ 11 সরবরাহ করে std::atomic<LONG>যাতে আপনি খাঁটি লোড / খাঁটি স্টোরগুলি অপ্টিমাইজড, বা পুনরায় অর্ডার করা, বা অন্য যে কোনও কিছু সমস্যা না করেই নিরাপদে লকলেস কোড লিখতে পারেন।
পিটার কর্ডেস

10

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


10

স্ট্যান্ডার্ড সি-তে, ব্যবহার volatileকরার মতো একটি জায়গা সিগন্যাল হ্যান্ডলারের সাথে রয়েছে with প্রকৃতপক্ষে, স্ট্যান্ডার্ড সি-তে, আপনি সিগন্যাল হ্যান্ডলারে নিরাপদে যা করতে পারেন তা হ'ল একটি volatile sig_atomic_tপরিবর্তনকে পরিবর্তন করা, বা দ্রুত প্রস্থান করা। প্রকৃতপক্ষে, আফাইক, স্ট্যান্ডার্ড সি তে এটিই একমাত্র জায়গা volatileযা অপরিজ্ঞাত আচরণ এড়াতে ব্যবহার করা প্রয়োজন।

আইএসও / আইইসি 9899: 2011 §7.14.1.1 signalফাংশন

¶5 যদি সিগন্যালটি abortবা raiseফাংশন কল করার ফলাফল ব্যতীত অন্য কোনও ঘটনা ঘটে থাকে তবে সিগন্যাল হ্যান্ডলারটি স্থায়ী বা থ্রেড স্টোরেজ সময়কাল সহ যে কোনও বস্তুকে উল্লেখ করে যা কোনও মান নির্ধারণের ব্যতীত অন্য কোনও লক-মুক্ত পরমাণু বস্তু নয় to হিসাবে ঘোষিত কোনও বস্তুতে volatile sig_atomic_t, বা সিগন্যাল হ্যান্ডলারটি abortফাংশন, _Exitফাংশন, quick_exitফাংশন, বা signalফাংশন ব্যতীত প্রথম আর্গুমেন্টের সাথে ফাংশন, সংকেতের সাথে অনুরূপ সংকেত সংখ্যার সমান প্রথম আর্গুমেন্টের সাথে যে কোনও ক্রিয়াকলাপ ডাকে যে অনুরোধের কারণ হয়েছিল হ্যান্ডলার। তদ্ব্যতীত, যদি signalফাংশনে এই জাতীয় কোনও কল একটি SIG_ERR রিটার্নে ফলাফল করে তবে এর মান errnoঅনির্দিষ্ট। 252)

252) কোনও সংকেত যদি অ্যাসিনক্রোনাস সিগন্যাল হ্যান্ডলার দ্বারা উত্পাদিত হয়, তবে আচরণটি সংজ্ঞায়িত।

এর মানে হল যে স্ট্যান্ডার্ড সি তে আপনি লিখতে পারেন:

static volatile sig_atomic_t sig_num = 0;

static void sig_handler(int signum)
{
    signal(signum, sig_handler);
    sig_num = signum;
}

এবং অন্য কিছু না।

সিগন্যাল হ্যান্ডলারে আপনি যা করতে পারেন সে সম্পর্কে পসিক্স অনেক বেশি হালকা, তবে এখনও সীমাবদ্ধতা রয়েছে (এবং সীমাবদ্ধতার একটি হ'ল স্ট্যান্ডার্ড আই / ও লাইব্রেরি - printf()এট - নিরাপদে ব্যবহার করা যাবে না)।


7

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

একই জিনিসটি একটি চলকের ক্ষেত্রে প্রযোজ্য যা আরও traditionalতিহ্যবাহী পরিবেশে একটি ভিন্ন থ্রেডে পরিবর্তিত হতে পারে, তবে সেখানে আমরা প্রায়শই সিঙ্ক্রোনাইজেশন কল করি, সুতরাং সংযোজকটি অপ্টিমাইজেশনের সাথে এতটা মুক্ত নয়।


7

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


7

এটি হিসাবে লক্ষ্য হিসাবে ব্যবহার করার পাশাপাশি, অস্থায়ী (টেমপ্লেট) রূপক ব্যবহার করা হয়। এটি দুর্ঘটনাজনিত ওভারলোডিং রোধ করতে ব্যবহার করা যেতে পারে, কারণ অস্থায়ী বৈশিষ্ট্য (কনস্টের মতো) ওভারলোড রেজোলিউশনে অংশ নেয়।

template <typename T> 
class Foo {
  std::enable_if_t<sizeof(T)==4, void> f(T& t) 
  { std::cout << 1 << t; }
  void f(T volatile& t) 
  { std::cout << 2 << const_cast<T&>(t); }

  void bar() { T t; f(t); }
};

এটি আইনী; উভয়ই ওভারলোডগুলি সম্ভাব্যভাবে কলযোগ্য এবং প্রায় একই রকম হয়। volatileওভারলোডের কাস্টটি আইনী কারণ আমরা জানি যে বার Tকোনওভাবেই অ-উদ্বায়ী হবে না। volatileসংস্করণ কঠোরভাবে খারাপ, যদিও, তাই কখনো জমিদার রেজোলিউশনের মনোনীত হলে অনুদ্বায়ী fপাওয়া যায়।

নোট করুন যে কোডটি কখনই volatileমেমরি অ্যাক্সেসের উপর নির্ভর করে না।


আপনি দয়া করে একটি উদাহরণ দিয়ে বিস্তারিত বলতে পারেন? এটি আমাকে আরও ভালভাবে বুঝতে সাহায্য করবে। ধন্যবাদ!
ব্যাটব্র্যাট

" অস্থির ওভারলোডের মধ্যে কাস্ট " একটি কাস্ট একটি সুস্পষ্ট রূপান্তর। এটি একটি সিনট্যাক্স নির্মাণ। অনেক লোক সেই বিভ্রান্তি তৈরি করে (এমনকি মানক লেখক)।
কৌতূহলী

6
  1. আপনার অবশ্যই এটি স্পিনলকগুলি পাশাপাশি কিছু (সমস্ত?) লক-ফ্রি ডেটা স্ট্রাকচার প্রয়োগ করতে ব্যবহার করতে হবে
  2. এটি পারমাণবিক ক্রিয়াকলাপ / নির্দেশাবলী সহ ব্যবহার করুন
  3. কম্পাইলারের বাগ (অপ্টিমাইজেশনের সময় ভুলভাবে উত্পন্ন কোড) কাটিয়ে উঠতে আমাকে একবার সাহায্য করেছে

5
আপনি একটি লাইব্রেরি, সংকলক অভ্যন্তরীণ বা ইনলাইনে সমাবেশ কোড ব্যবহার করে ভাল। অস্থিরতা অবিশ্বাস্য।
জ্যান লিংস

1
1 এবং 2 উভয়ই পারমাণবিক অপারেশনগুলি ব্যবহার করে তবে অস্থিরতা পারমাণবিক শব্দার্থবিজ্ঞান সরবরাহ করে না এবং পারমাণবিকের প্ল্যাটফর্ম-নির্দিষ্ট প্রয়োগগুলি অস্থির ব্যবহারের প্রয়োজনকে ছাড়িয়ে যায়, সুতরাং 1 এবং 2 এর জন্য আমি একমত নই, এগুলির জন্য আপনার অস্থির প্রয়োজন হবে না।

পারমাণবিক শব্দার্থ সরবরাহ সরবরাহের বিষয়ে কে কিছু বলে? আমি বলেছিলাম পারমাণবিক ক্রিয়াকলাপের সাথে আপনার অস্থির ব্যবহার করা দরকার এবং আপনি যদি মনে করেন না যে win32 এপিআইয়ের ইন্টারলকড অপারেশনগুলির ঘোষণাপত্রের সত্য চেহারাটি (এই লোকটি তার উত্তরে এটিও ব্যাখ্যা করেছিল)
ম্লাদেন জানকোভিয়

4

volatileশব্দ যে বস্তু উপায়গুলির কম্পাইলার দ্বারা নির্ধারণ করা যাবে না পরিবর্তন করতে পারেন কোন optimisations আবেদন করা থেকে কম্পাইলার প্রতিরোধ উদ্দেশ্যে।

হিসাবে ঘোষিত অবজেক্টগুলি volatileঅপ্টিমাইজেশন থেকে বাদ দেওয়া হয়েছে কারণ যে কোনও সময় বর্তমান কোডের আওতার বাইরে কোড দ্বারা তাদের মানগুলি পরিবর্তন করা যেতে পারে। volatileপূর্বের নির্দেশ একই বস্তু থেকে কোনও মান জিজ্ঞাসা করে, এমনকি যদি অনুরোধ করা হয় এমন স্থানে অস্থায়ী নিবন্ধে তার মান রাখার পরিবর্তে সিস্টেমটি সর্বদা স্মৃতি অবস্থান থেকে কোনও বস্তুর বর্তমান মান পড়বে।

নিম্নলিখিত বিষয়গুলি বিবেচনা করুন

1) গ্লোবাল ভেরিয়েবলগুলি সুযোগের বাইরে একটি বিঘ্নিত পরিষেবার রুটিন দ্বারা সংশোধিত।

2) বহু-থ্রেডযুক্ত অ্যাপ্লিকেশনের মধ্যে গ্লোবাল ভেরিয়েবল।

আমরা যদি অস্থির যোগ্যতা ব্যবহার না করি তবে নিম্নলিখিত সমস্যাগুলি দেখা দিতে পারে

1) কোডটি অপ্টিমাইজেশন চালু করার সময় প্রত্যাশার মতো কাজ করতে পারে না।

2) কোড বিঘ্ন সক্ষম এবং সক্ষম হয়ে থাকে তখন প্রত্যাশা অনুযায়ী কাজ করতে পারে না।

উদ্বায়ী: একজন প্রোগ্রামারের সেরা বন্ধু

https://en.wikipedia.org/wiki/Volatile_(computer_programming)


আপনার পোস্ট করা লিঙ্কটি অত্যন্ত পুরানো এবং বর্তমানের সেরা অনুশীলনগুলিকে প্রতিফলিত করে না।
টিম সেগুইন

2

সংস্থাপককে কিছু ভেরিয়েবলের অ্যাক্সেসের অনুকূলতা না দেওয়ার জন্য (যা একটি থ্রেড বা একটি বিঘ্নিত রুটিন দ্বারা সংশোধন করা যেতে পারে) অপরিহার্য কীওয়ার্ডটি ব্যবহৃত হওয়ার পাশাপাশি, এটি কয়েকটি সংকলক বাগগুলি সরানোর জন্যও ব্যবহার করা যেতে পারে - হ্যাঁ এটি পারে be ---।

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


3
সংকলকটি উদ্বায়ীদের অ্যাক্সেসকে অনুকূলিত করে না এমন ধারণাটি এটি একটি ত্রুটিযুক্ত অনুমান। মানটি অপ্টিমাইজেশন সম্পর্কে কিছুই জানে না। সংকলকটির মানটি যা নির্দেশ করে তা সম্মান করার জন্য প্রয়োজনীয়, তবে এটি এমন কোনও অপ্টিমাইজেশন করতে বিনামূল্যে যা সাধারণ আচরণে হস্তক্ষেপ না করে।
টার্মিনাস

3
আমার অভিজ্ঞতা থেকে জিসিসি আর্মের সমস্ত অপ্টিমাইজেশন "বাগ" এর 99.9% প্রোগ্রামারটির ত্রুটি। এটি এই উত্তরটির জন্য প্রযোজ্য কিনা ধারণা নেই। সাধারণ বিষয়ের উপর কেবল একটি রেন্ট
31:11

@ টারমিনাস "সংকলকটি উদ্বায়ীদের অ্যাক্সেসকে অনুকূল করে না " এই ধারণাটি একটি ত্রুটিযুক্ত অনুমান ?
কৌতূহলী

2

আপনার প্রোগ্রামটি volatileকীওয়ার্ড ছাড়াও কাজ করছে বলে মনে হচ্ছে ? সম্ভবত এটি কারণ:

পূর্বে উল্লিখিত হিসাবে volatileকীওয়ার্ড যেমন ক্ষেত্রে সাহায্য করে

volatile int* p = ...;  // point to some memory
while( *p!=0 ) {}  // loop until the memory becomes zero

তবে একবার বাহ্যিক বা নন-ইনলাইন ফাংশন বলা হয়ে গেলে প্রায় কোনও প্রভাব নেই বলে মনে হচ্ছে। উদাহরণ:

while( *p!=0 ) { g(); }

তারপরে বা volatileপ্রায় একই ফলাফল উত্পন্ন হয়।

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

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

অতএব আমি volatileআপনার প্রোগ্রামটি কাজ না করে দেখে মনে হচ্ছে কীওয়ার্ড যুক্ত করার পরামর্শ দিই । এটি ভবিষ্যতের পরিবর্তনের ক্ষেত্রে অভিপ্রায়টিকে আরও স্পষ্ট এবং আরও দৃ .় করে তোলে।


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

একটি ফাংশন দ্বারা কল (বা এর শব্দার্থক এর "ইনলাইনিং") এর শারীরিক সংক্ষিপ্ত বিবরণ এড়ানো যা একটির volatileফাংশন পয়েন্টার দ্বারা সংকলক দ্বারা প্রদর্শিত হয় (এমনকি বৈশ্বিক অপ্টিমাইজেশনের সাথে সংযোগ সময়েও) সম্ভব :void (* volatile fun_ptr)() = fun; fun_ptr();
কৌতূহলী

2

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

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

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

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

  2. volatileমুটেক্স দ্বারা রক্ষিত সমস্ত অবজেক্টগুলিকে যোগ্য হিসাবে চিহ্নিত করুন - যা মুটেেক্স অর্জনের পরে এবং ছাড়ার আগে সমস্ত অ্যাক্সেস ঘটে তবে প্রয়োজনীয় হওয়া উচিত নয়।

  3. যেন সমস্ত বস্তু যে যোগ্যতাসম্পন্ন নয় কোড জেনারেট করতে কম্পাইলার বলপূর্বক অপ্টিমাইজেশান স্তর 0 ব্যবহার করুন registerহয় volatile

  4. জিসিসি-নির্দিষ্ট নির্দেশাবলী ব্যবহার করুন।

বিপরীতে, একটি উচ্চ-মানের সংকলক ব্যবহার করা যখন আইসিসির মতো সিস্টেম প্রোগ্রামিংয়ের জন্য আরও উপযুক্ত, একটির অন্য বিকল্প থাকতে পারে:

  1. নিশ্চিত করুন যে একটি volatileযোগ্যতুল্য লিখন সর্বত্র সম্পাদিত হয় একটি অর্জন বা প্রকাশের প্রয়োজন।

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


1

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


1

সমস্ত উত্তর চমৎকার। তবে তার শীর্ষে, আমি একটি উদাহরণ ভাগ করতে চাই।

নীচে একটি সামান্য সিপিপি প্রোগ্রাম:

#include <iostream>

int x;

int main(){
    char buf[50];
    x = 8;

    if(x == 8)
        printf("x is 8\n");
    else
        sprintf(buf, "x is not 8\n");

    x=1000;
    while(x > 5)
        x--;
    return 0;
}

এখন, উপরের কোডটির সমাবেশটি তৈরি করতে দিন (এবং আমি এখানে কেবল প্রাসঙ্গিকতার সেই অংশগুলিই প্রম্পট করব):

সমাবেশ উত্পন্ন করার আদেশ:

g++ -S -O3 -c -fverbose-asm -Wa,-adhln assembly.cpp

এবং সমাবেশ:

main:
.LFB1594:
    subq    $40, %rsp    #,
    .seh_stackalloc 40
    .seh_endprologue
 # assembly.cpp:5: int main(){
    call    __main   #
 # assembly.cpp:10:         printf("x is 8\n");
    leaq    .LC0(%rip), %rcx     #,
 # assembly.cpp:7:     x = 8;
    movl    $8, x(%rip)  #, x
 # assembly.cpp:10:         printf("x is 8\n");
    call    _ZL6printfPKcz.constprop.0   #
 # assembly.cpp:18: }
    xorl    %eax, %eax   #
    movl    $5, x(%rip)  #, x
    addq    $40, %rsp    #,
    ret 
    .seh_endproc
    .p2align 4,,15
    .def    _GLOBAL__sub_I_x;   .scl    3;  .type   32; .endef
    .seh_proc   _GLOBAL__sub_I_x

আপনি সমাবেশে দেখতে পারেন যে সমাবেশ কোডটি তৈরি করা হয়নি sprintfকারণ সংকলকটি ধরে নিয়েছিল যে xপ্রোগ্রামের বাইরে পরিবর্তন হবে না। whileলুপের ক্ষেত্রেও একই অবস্থা । whileঅপ্টিমাইজেশনের কারণে লুপটি সম্পূর্ণরূপে অপসারণ করা হয়েছিল কারণ সংকলক এটি একটি অকেজো কোড হিসাবে দেখেছিল এবং এভাবে সরাসরি ( দেখায় ) নির্ধারিত 5হয় ।xmovl $5, x(%rip)

সমস্যা দেখা দেয় যখন যদি একটি বহিস্থিত প্রক্রিয়া / হার্ডওয়্যার মান পরিবর্তন হবে কি xমধ্যে কোথাও x = 8;এবং if(x == 8)। আমরা elseব্লকটি কাজ করার আশা করব তবে দুর্ভাগ্যক্রমে সংকলকটি সেই অংশটি ছাঁটাই করেছে।

এখন, এই সমাধানের জন্য, যাতে assembly.cpp, আমাদের পরিবর্তন করা যাক int x;করতে volatile int x;এবং দ্রুত উত্পন্ন সমাবেশ কোড দেখুন:

main:
.LFB1594:
    subq    $104, %rsp   #,
    .seh_stackalloc 104
    .seh_endprologue
 # assembly.cpp:5: int main(){
    call    __main   #
 # assembly.cpp:7:     x = 8;
    movl    $8, x(%rip)  #, x
 # assembly.cpp:9:     if(x == 8)
    movl    x(%rip), %eax    # x, x.1_1
 # assembly.cpp:9:     if(x == 8)
    cmpl    $8, %eax     #, x.1_1
    je  .L11     #,
 # assembly.cpp:12:         sprintf(buf, "x is not 8\n");
    leaq    32(%rsp), %rcx   #, tmp93
    leaq    .LC0(%rip), %rdx     #,
    call    _ZL7sprintfPcPKcz.constprop.0    #
.L7:
 # assembly.cpp:14:     x=1000;
    movl    $1000, x(%rip)   #, x
 # assembly.cpp:15:     while(x > 5)
    movl    x(%rip), %eax    # x, x.3_15
    cmpl    $5, %eax     #, x.3_15
    jle .L8  #,
    .p2align 4,,10
.L9:
 # assembly.cpp:16:         x--;
    movl    x(%rip), %eax    # x, x.4_3
    subl    $1, %eax     #, _4
    movl    %eax, x(%rip)    # _4, x
 # assembly.cpp:15:     while(x > 5)
    movl    x(%rip), %eax    # x, x.3_2
    cmpl    $5, %eax     #, x.3_2
    jg  .L9  #,
.L8:
 # assembly.cpp:18: }
    xorl    %eax, %eax   #
    addq    $104, %rsp   #,
    ret 
.L11:
 # assembly.cpp:10:         printf("x is 8\n");
    leaq    .LC1(%rip), %rcx     #,
    call    _ZL6printfPKcz.constprop.1   #
    jmp .L7  #
    .seh_endproc
    .p2align 4,,15
    .def    _GLOBAL__sub_I_x;   .scl    3;  .type   32; .endef
    .seh_proc   _GLOBAL__sub_I_x

এখানে আপনি দেখতে পারেন জন্য সমাবেশ কোড sprintf, printfএবং whileলুপ উত্পন্ন হয়। সুবিধাটি হ'ল xভেরিয়েবলটি যদি কোনও বাহ্যিক প্রোগ্রাম বা হার্ডওয়্যার দ্বারা পরিবর্তন করা হয় sprintfতবে কোডের কিছু অংশ কার্যকর করা হবে। এবং অনুরূপভাবে whileলুপটি এখন ব্যস্ততার জন্য ব্যবহৃত হতে পারে।


0

অন্যান্য উত্তরগুলি ইতিমধ্যে কিছু অপ্টিমাইজেশন এড়ানো উল্লেখ করেছে:

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

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

একটি অস্থির পঠন একটি ইনপুট অপারেশনের মতো (যেমন scanfবা এর ব্যবহার cin): মানটি প্রোগ্রামের বাইরের দিক থেকে আসে বলে মনে হয়, সুতরাং কোনও মানের যে কোনও সংখ্যার উপর নির্ভরতা থাকে তার পরে এটি শুরু করা দরকার

একটি অস্থির রাইটিং একটি আউটপুট অপারেশনের মতো (যেমন printfবা এর ব্যবহার cout): মানটি প্রোগ্রামের বাইরে বলে মনে হয়, সুতরাং যদি মানটি কোনও গণনার উপর নির্ভর করে, এটি আগে শেষ করা দরকার

সুতরাং একজোড়া অস্থির পড়া / লেখাকে বেঞ্চমার্ককে নিয়ন্ত্রণ করতে এবং সময় পরিমাপকে অর্থবহ করে তোলা যায়

অস্থিরতা ছাড়াই, আপনার গণনা আগে সংকলক দ্বারা শুরু করা যেতে পারে, কারণ সময় পরিমাপের মতো ফাংশনগুলির সাথে গণনা পুনরায় রোধ করা কিছুই রোধ করতে পারে না

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