এম্বেড থাকা সি বিকাশে অস্থির ব্যবহার


44

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

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

  1. volatileকীওয়ার্ড ব্যবহার না করেই

    // Includes
    #include "adcDriver.h"
    
    // Global variables
    uint16_t adcValue;
    
    // Some code
    void readFromADC(void)
    {
       adcValue = readADC();
    }
    
  2. volatileকীওয়ার্ড ব্যবহার করে

    // Includes
    #include "adcDriver.h"
    
    // Global variables
    volatile uint16_t adcValue;
    
    // Some code
    void readFromADC(void)
    {
       adcValue = readADC();
    }
    

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


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

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

2
আপনি উভয় সংস্করণ দ্বারা উত্পাদিত এসেম্বলারের তুলনা করেছেন? এটি আপনাকে হুডের নীচে কী ঘটছে তা দেখাতে হবে
মাউগ

3
@ স্টার্ক: বায়োস? একটি মাইক্রোকন্ট্রোলারে? ক্যাশিংয়ের নিয়ম এবং মেমরি মানচিত্রের মধ্যে নকশার সামঞ্জস্য রেখে মেমরি-ম্যাপযুক্ত I / O স্থানটি নন-ক্যাশেযোগ্য হবে (যদি আর্কিটেকচারে প্রথম স্থানে ডেটা ক্যাশে থাকে তবে এটি নিশ্চিত নয়)। তবে মেমরি কন্ট্রোলার ক্যাশে অস্থির কোনও সম্পর্ক নেই।
বেন ভয়েগট

1
@ ডেভিস্লোর ভাষার মানটির সাধারণভাবে আরও কিছু বলার দরকার নেই। একটি অস্থির অবজেক্টে পড়া একটি আসল বোঝা সম্পাদন করবে (যদিও সংকলকটি সম্প্রতি একটি করেছে এবং সাধারণত মূল্যটি কী তা জানত) এবং এই জাতীয় অবজেক্টটিতে একটি লেখা একটি সত্যিকারের স্টোর সম্পাদন করবে (এমনকি যদি একই বস্তু থেকে একই মানটি পড়েছিল) )। সুতরাং if(x==1) x=1;লেখায় কোনও অস্থির জন্য অপ্টিমাইজ করা যেতে পারে xএবং যদি xউদ্বায়ী হয় তবে অনুকূলিত হতে পারে না । OTOH যদি বাহ্যিক ডিভাইসগুলিতে অ্যাক্সেসের জন্য বিশেষ নির্দেশাবলীর প্রয়োজন হয় তবে সেগুলি যুক্ত করা আপনার পক্ষে হবে (f.ex. যদি কোনও মেমরির পরিসীমাটি লেখার প্রয়োজন হয়)।
কৌতূহলী

উত্তর:


87

একটি সংজ্ঞা volatile

volatileসংকলককে জানায় যে সংকলকটি না জেনে ভেরিয়েবলের মান পরিবর্তন হতে পারে। সুতরাং সংকলকটি ধরে নিতে পারে মানটির কোনও পরিবর্তন হয়নি কারণ কেবলমাত্র সি প্রোগ্রামটি এটি পরিবর্তন করে নি।

অন্যদিকে, এর অর্থ হ'ল ভেরিয়েবলের মান প্রয়োজন (পড়ুন) অন্য কোথাও সংকলকটি জানেন না, সুতরাং এটি অবশ্যই নিশ্চিত করতে হবে যে ভেরিয়েবলের প্রতিটি অ্যাসাইনমেন্ট আসলে রাইটিং অপারেশন হিসাবে সম্পাদিত হয়।

ব্যবহারের ক্ষেত্রে

volatile যখন প্রয়োজন হয়

  • হার্ডওয়্যার রেজিস্টারগুলিকে (বা মেমরি-ম্যাপযুক্ত I / O) ভেরিয়েবল হিসাবে উপস্থাপন করতে হবে - এমনকি রেজিস্টারটি কখনই পড়তে হবে না, সংকলকটি অবশ্যই "বোকা প্রোগ্রামার" ভেবে লেখার ক্রিয়াটি এড়িয়ে চলবে না he তিনি / সে একটি ভেরিয়েবলের মধ্যে একটি মান সংরক্ষণ করার চেষ্টা করে আর কখনও পড়তে হবে না He তিনি লেখার বিষয়টি খেয়ালও করবেন না আমরা লেখাটি বাদ দিই কিনা। " বিপরীতক্রমে, এমনকি যদি প্রোগ্রামটি কখনও ভেরিয়েবলের কাছে কোনও মান না লিখে, তার মানটি এখনও হার্ডওয়্যার দ্বারা পরিবর্তিত হতে পারে।
  • এক্সিকিউটিভ প্রসঙ্গে (যেমন আইএসআর / মূল প্রোগ্রাম) এর মধ্যে ভাগ করে নেওয়া পরিবর্তনগুলি (@ কেক্রামোর ​​উত্তর দেখুন)

এর প্রভাব volatile

যখন কোনও ভেরিয়েবল ঘোষিত হয় volatileতখন অবশ্যই তা নিশ্চিত করতে হবে যে প্রোগ্রাম কোডে এটির প্রতিটি অ্যাসাইনমেন্ট প্রকৃত রাইটিং অপারেশনে প্রতিফলিত হয়েছে এবং প্রোগ্রাম কোডে প্রতিটি পঠিত মান (এমএম্যাপ করা) মেমরি থেকে পড়ে reads

অ-উদ্বায়ী ভেরিয়েবলের জন্য, সংকলকটি ধরে নিচ্ছে যে / যখন ভেরিয়েবলের মান পরিবর্তন হয় এবং কোডটি বিভিন্ন উপায়ে অপ্টিমাইজ করতে পারে তা জানে।

একটির জন্য, সংকলক সিপিইউ রেজিস্টারে মান রেখে মেমরিটিতে পঠন / লেখার সংখ্যা হ্রাস করতে পারে।

উদাহরণ:

void uint8_t compute(uint8_t input) {
  uint8_t result = input + 2;
  result = result * 2;
  if ( result > 100 ) {
    result -= 100;
  }
  return result;
}

এখানে, সংকলক সম্ভবত resultভেরিয়েবলের জন্য র‍্যাম বরাদ্দ করবে না এবং মাঝারি মানগুলি আর কোথাও সংরক্ষণ করবে না তবে সিপিইউ রেজিস্টারে থাকবে।

যদি resultঅস্থিরতা থাকে resultতবে সি কোডের প্রতিটি ঘটনার জন্য র‍্যাম (বা একটি আই / ও পোর্ট) অ্যাক্সেস করার জন্য সংকলকটির প্রয়োজন হবে, যার ফলে নিম্ন কার্যকারিতা দেখাবে।

দ্বিতীয়ত, সংকলক পারফরম্যান্স এবং / অথবা কোড আকারের জন্য অ-উদ্বায়ী ভেরিয়েবলগুলির ক্রিয়াকলাপ পুনরায় অর্ডার করতে পারে। সাধারণ উদাহরণ:

int a = 99;
int b = 1;
int c = 99;

পুনরায় আদেশ দেওয়া যেতে পারে

int a = 99;
int c = 99;
int b = 1;

যা কোনও এসেম্বলারের নির্দেশ সংরক্ষণ করতে পারে কারণ মানটি 99দুটিবার লোড করতে হবে না।

তাহলে a, bএবং cউদ্বায়ী ছিল কম্পাইলার নির্দেশাবলী যা সঠিক অনুক্রমে মান নির্ধারণ হিসাবে তারা কর্মসূচি দেওয়া হয় নির্গত করতে হবে।

অন্যান্য ক্লাসিক উদাহরণটি এরকম:

volatile uint8_t signal;

void waitForSignal() {
  while ( signal == 0 ) {
    // Do nothing.
  }
}

যদি, এই ক্ষেত্রে signalনা হয় volatile, তবে সংকলকটি 'চিন্তা' করবে যা while( signal == 0 )একটি অসীম লুপ হতে পারে (কারণ লুপের অভ্যন্তরেsignal কোড দ্বারা কখনই পরিবর্তন করা যাবে না ) এবং এর সমতুল্য উত্পন্ন করতে পারে

void waitForSignal() {
  if ( signal != 0 ) {
    return; 
  } else {
    while(true) { // <-- Endless loop!
      // do nothing.
    }
  }
}

volatileমানগুলি পরিচালনা করা বিবেচনা করুন

উপরে বর্ণিত হিসাবে, কোনও volatileপরিবর্তনশীল যখন কার্যত প্রয়োজনের চেয়ে বেশি বার অ্যাক্সেস করা হয় তখন একটি পারফরম্যান্স পেনাল্টি প্রবর্তন করতে পারে। এই সমস্যাটি প্রশমিত করতে আপনি একটি অ-উদ্বায়ী ভেরিয়েবলের জন্য বরাদ্দ করে মানটিকে "আন-ভোল্টাইল" করতে পারেন, যেমন

volatile uint32_t sysTickCount;

void doSysTick() {
  uint32_t ticks = sysTickCount; // A single read access to sysTickCount

  ticks = ticks + 1; 

  setLEDState( ticks < 500000L );

  if ( ticks >= 1000000L ) {
    ticks = 0;
  }
  sysTickCount = ticks; // A single write access to volatile sysTickCount
}

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

এই কৌশলটির সাহায্যে আপনি মূলত কম্পাইলারটি অ-উদ্বায়ী ভেরিয়েবলগুলির জন্য ঠিক একই কাজটি করেন, অর্থাত্ যখন স্মৃতি থেকে পড়তে হয় কেবল তখনই তা পড়ুন, কিছু সময় নিবন্ধকে মান রাখুন এবং যখন মেমরিটিতে ফিরে যেতে হয় কেবল তখনই লিখুন ; তবে এই বার, আপনি / যখন পড়তে / লিখতে হবে তা সংকলকটির চেয়ে ভাল জানেন , সুতরাং আপনি এই অপটিমাইজেশন টাস্ক থেকে সংকলককে মুক্তি দিন এবং নিজেই করুন।

সীমাবদ্ধতা volatile

অ-পরমাণু প্রবেশাধিকার

volatileমাল্টি-ওয়ার্ড ভেরিয়েবলগুলিতে পারমাণবিক অ্যাক্সেস সরবরাহ করে না । এই ক্ষেত্রে, আপনাকে ব্যবহারের পাশাপাশি অন্য উপায় দ্বারা পারস্পরিক বর্জনীয় সরবরাহ করতে হবে volatile। এভিআর, আপনি ব্যবহার করতে পারেন ATOMIC_BLOCKথেকে <util/atomic.h>বা সহজ cli(); ... sei();কল। সংশ্লিষ্ট ম্যাক্রোগুলি মেমোরি বাধা হিসাবেও কাজ করে, যা অ্যাক্সেসের ক্রম হিসাবে আসে যখন তা গুরুত্বপূর্ণ:

আদেশ কার্যকর

volatileকেবলমাত্র অন্যান্য অস্থির ভেরিয়েবলের প্রতি শ্রদ্ধার সাথে কঠোর মৃত্যুদণ্ডের আদেশ চাপায়। এর অর্থ এটি উদাহরণস্বরূপ

volatile int i;
volatile int j;
int a;

...

i = 1;
a = 99;
j = 2;

প্রথমে 1 বরাদ্দ iএবং তারপরে 2 থেকে 2 প্রদানের গ্যারান্টিযুক্ত j। কিন্তু, ব্যাপারটা না নিশ্চিত যে aমধ্যবর্তী নিয়োগ করা হবে; সংকলক কোড স্নিপেটের আগে বা পরে সেই কাজটি করতে পারে, মূলত যে কোনও সময়ে প্রথম (দৃশ্যমান) পড়ার আগে পর্যন্ত a

যদি এটি উল্লিখিত ম্যাক্রোগুলির মেমরি বাধা না থাকে তবে সংকলকটিকে অনুবাদ করার অনুমতি দেওয়া হত

uint32_t x;

cli();
x = volatileVar;
sei();

প্রতি

x = volatileVar;
cli();
sei();

অথবা

cli();
sei();
x = volatileVar;

(সম্পূর্ণতার স্বার্থে আমি যে মেমরি বাধা, Sei / CLI ম্যাক্রো ক্ষেত্রে প্রযোজ্য মত বলতে হবে, আসলে ব্যবহার নিবারণ করতে পারে volatile, যদি সব ব্যবহারের এই বাধা দিয়ে বন্ধনী করা হয়।)


7
পারফরম্যান্সের জন্য আন-
ভোল্টিলিংয়ের

3
আমি সর্বদা আইএসও / আইইসি 9899: 1999 6.7.3 (6) এ অস্থির সংজ্ঞা উল্লেখ করতে চাই : An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. আরও লোকেরা এটি পড়তে হবে should
জেরোইন 3

3
এটি উল্লেখ করার মতো হতে পারে cli/ seiযদি আপনার একমাত্র লক্ষ্য কোনও মেমরি বাধা অর্জন করা হয়, বাধা রোধ না করে তবে খুব ভারী সমাধান হয়। এই ম্যাক্রোগুলি প্রকৃত cli/ seiনির্দেশাবলী এবং অতিরিক্ত ক্লোবার মেমরি উত্পন্ন করে এবং এটি এই ক্লোবারিং যার ফলে বাধা দেয়। বাধা নিষ্ক্রিয় না করে শুধুমাত্র একটি মেমোরি বাধা থাকার জন্য আপনি নিজের ম্যাক্রোটি শরীরের সাথে __asm__ __volatile__("":::"memory")(যেমন মেমরি ক্লোবারের সাথে খালি অ্যাসেম্বলি কোড) সংজ্ঞা দিতে পারেন।
Ruslan

3
@ নিক হার্টলি নং সি 17 5.1.2.3 §6 পর্যবেক্ষণযোগ্য আচরণের সংজ্ঞা দেয় : "বিমূর্ত যন্ত্রের নিয়ম অনুসারে অস্থির বস্তুগুলির প্রবেশের কঠোরভাবে মূল্যায়ন করা হয়।" সি স্ট্যান্ডার্ডটি সামগ্রিকভাবে মেমরির বাধা কোথায় প্রয়োজন সে সম্পর্কে সত্যই পরিষ্কার নয়। যে অভিব্যক্তিটি ব্যবহার করে volatileতার শেষে একটি সিকোয়েন্স পয়েন্ট থাকে এবং এর পরে সমস্ত কিছু অবশ্যই "পরে ক্রম" হয়। অর্থ যে অভিব্যক্তি হ'ল ধরণের স্মৃতি বাধা bar সংকলক বিক্রেতারা প্রোগ্রামারের উপরে মেমরি বাধাগুলির দায়বদ্ধ করতে সমস্ত ধরণের পৌরাণিক কাহিনী ছড়িয়ে দেওয়ার পছন্দ করেছেন তবে এটি "বিমূর্ত মেশিন" এর বিধি লঙ্ঘন করে।
লুন্ডিন

2
@ জিমিবি লোকাল অস্থিরতা কোডের মতো হতে পারে volatile data_t data = {0}; set_mmio(&data); while (!data.ready);
ম্যাকিয়েজ পাইচোটকা

13

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

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

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

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


6
আমি এই উত্তরের সাথে একমত তবে "ম্যাগনিটিউডস ধীর" খুব মারাত্মক শোনায়।
kkrambo

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

7
এম্বেড (মাইক্রোকন্ট্রোলার) সিস্টেমে র‌্যাম অ্যাক্সেসের জন্য পেনাল্টি প্রায়শই অনেক কম থাকে। এভিআর, উদাহরণস্বরূপ, র‌্যাম থেকে পড়তে বা লেখার জন্য মাত্র দুটি সিপিইউ চক্র গ্রহণ করুন (একটি রেজিস্টার-রেজিস্টার সরানো একটি চক্র গ্রহণ করে), সুতরাং নিবন্ধগুলিতে জিনিস রাখার সঞ্চয় (তবে বাস্তবে কখনও পৌঁছায় না) সর্বোচ্চ। অ্যাক্সেস প্রতি 2 ঘড়ি চক্র। - অবশ্যই, তুলনামূলকভাবে বলতে গেলে, এক্স থেকে র‌্যামে একটি মান সংরক্ষণ করা, তারপরে তত্ক্ষণাত এই মানটি আরও নিরূপণের জন্য রেজিস্টার এক্স-এ পুনরায় লোড করাতে 0 চক্রের পরিবর্তে 2x2 = 4 লাগবে (কেবলমাত্র মানটি এক্সে রাখার সময়), এবং তাই অসীম ধীর :)
জিমিবি

1
"নির্দিষ্ট ভেরিয়েবলের কাছে লেখা বা পড়া" প্রসঙ্গে এটি 'আকারের ধীরগতি' হ্যাঁ। তবে এমন একটি সম্পূর্ণ প্রোগ্রামের প্রসঙ্গে যা সম্ভবত একবারে একটি পরিবর্তনশীল থেকে বারবার পড়া / লেখার চেয়ে উল্লেখযোগ্যভাবে আরও বেশি করে, না, সত্যই নয়। সেক্ষেত্রে সামগ্রিক পার্থক্য সম্ভবত 'ক্ষুদ্র থেকে অবহেলিত' is পারফরম্যান্স সম্পর্কে দৃ .়তা দেওয়ার সময়, যত্নবান হওয়া উচিত, যদি দাবিটি নির্দিষ্ট কোনও অপের সাথে বা সামগ্রিকভাবে কোনও প্রোগ্রামের সাথে সম্পর্কিত হয় তবে তা স্পষ্ট করে জানাতে হবে। X 300x এর একটি ফ্যাক্টর দ্বারা খুব কম ব্যবহৃত অপ্টটি ধীরে ধীরে নামানো প্রায় কখনও বড় ব্যাপার নয়।
aroth

1
তুমি বলতে চাচ্ছ, শেষ বাক্যটি? "অকালীন অপটিমাইজেশন হ'ল সমস্ত মন্দের মূল" অর্থে এটি আরও অনেক কিছু বোঝায়। স্পষ্টতই আপনার volatileসমস্ত কিছুর জন্য কেবল ব্যবহার করা উচিত নয় , তবে আপনারা মনে করেন যে, প্রাকৃতিকভাবে পারফরম্যান্স উদ্বেগের কারণে এটি বৈধভাবে ডেকে আনা হয়েছে সে ক্ষেত্রেও আপনাকে এ থেকে বিরত থাকতে হবে না।
aroth

9

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

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


2
অবশ্যই অন্যান্য ব্যবহারিক ব্যবহারের উপস্থিতি রয়েছে তবে ইমো এটি সবচেয়ে সাধারণ।
ভিসাতচু

1
যদি মানটি কেবলমাত্র একটি আইএসআর-তে পড়ে থাকে (এবং প্রধান () থেকে পরিবর্তিত হয় তবে মাল্টি বাইট ভেরিয়েবলের জন্য এটিমিক অ্যাক্সেসের গ্যারান্টি দিতে আপনাকে সম্ভাব্যভাবে অস্থির ব্যবহার করতে হবে।
Rev1.0

15
@ রেভ ১.০ না, অস্থিরতা শৌখিনতার গ্যারান্টি দেয় না । সেই উদ্বেগকে আলাদাভাবে সমাধান করতে হবে।
ক্রিস স্ট্রাটন

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

3
"একটি বৈশ্বিক পরিবর্তনশীল চিহ্নিত করুন যা একটি বিঘ্নিত হ্যান্ডলারে লিখিত আছে" ন্যাপ। এটি একটি পরিবর্তনশীল চিহ্নিত করতে; গ্লোবাল বা অন্যথায়; এটি সংকলক বোঝার বাইরের কিছু দ্বারা পরিবর্তিত হতে পারে। বাধা প্রয়োজন নেই। এটি ভাগ করা মেমোরি বা কেউ স্মৃতিতে একটি তদন্ত আটকে থাকতে পারে (40 বছরের চেয়ে আধুনিক কোনও কিছুর জন্য সুপারিশ করা হয় না)
UKMonkey

9

volatileএম্বেড থাকা সিস্টেমগুলিতে আপনাকে অবশ্যই দুটি ব্যবহার করতে হবে ।

  • একটি হার্ডওয়্যার রেজিস্টার থেকে পড়া যখন।

    তার মানে, মেমরি-ম্যাপযুক্ত নিজেই নিবন্ধভুক্ত করুন, এমসিইউর ভিতরে হার্ডওয়্যার পেরিফেরিয়ালগুলির অংশ। এটিতে সম্ভবত "ADC0DR" এর মতো কিছু ক্রিপ্টিক নাম থাকবে। এই রেজিস্টারটি অবশ্যই সি কোডে সংজ্ঞায়িত করা উচিত, কোনও কোনও সরঞ্জাম বিক্রেতার দ্বারা সরবরাহকারীর ম্যাপের মাধ্যমে বা নিজের দ্বারা yourself এটি নিজে করতে, আপনি করতেন (16 বিট রেজিস্টার ধরে ধরে):

    #define ADC0DR (*(volatile uint16_t*)0x1234)

    যেখানে এমসিইউ রেজিস্টার ম্যাপ করেছে সেখানে 0x1234 ঠিকানা। যেহেতু volatileইতিমধ্যে উপরের ম্যাক্রোর অংশ, তাই এতে যে কোনও অ্যাক্সেস অস্থির-যোগ্য হবে। সুতরাং এই কোডটি ভাল:

    uint16_t adc_data;
    adc_data = ADC0DR;
  • আইএসআর ফলাফল ব্যবহার করে কোনও আইএসআর এবং সম্পর্কিত কোডের মধ্যে কোনও ভেরিয়েবল ভাগ করার সময়।

    আপনার যদি এরকম কিছু থাকে:

    uint16_t adc_data = 0;
    
    void adc_stuff (void)
    {
      if(adc_data > 0)
      {
        do_stuff(adc_data);
      } 
    }
    
    interrupt void ADC0_interrupt (void)
    {
      adc_data = ADC0DR;
    }

    তারপরে সংকলকটি মনে করতে পারে: "অ্যাডিসিডিটা সর্বদা 0 থাকে কারণ এটি কোথাও আপডেট হয় না And এবং এটি ADC0_interrupt () ফাংশনটি কখনই ডাকা হয় না, সুতরাং ভেরিয়েবল পরিবর্তন করা যায় না"। সংকলক সাধারণত বুঝতে পারে না যে বাধা সফ্টওয়্যার দ্বারা নয়, হার্ডওয়্যার দ্বারা ডাকা হয়। সুতরাং সংকলকটি গিয়ে কোডটি সরিয়ে দেয় if(adc_data > 0){ do_stuff(adc_data); }কারণ এটি মনে করে যে এটি কখনই সত্য হতে পারে না, ফলে একটি খুব অদ্ভুত এবং হার্ড-টু-ডিবাগ বাগ হয়।

    ঘোষণা দিয়ে adc_data volatile, সংকলকটিকে এ জাতীয় কোনও অনুমান করার অনুমতি দেওয়া হয় না এবং এটি ভেরিয়েবলের অ্যাক্সেসকে অপ্টিমাইজ করার অনুমতি দেয় না।


গুরুত্বপূর্ণ নোট:

  • একটি আইএসআর সর্বদা হার্ডওয়্যার ড্রাইভারের ভিতরে ঘোষণা করা হবে। এই ক্ষেত্রে, এডিসি আইএসআরটি এডিসি ড্রাইভারের অভ্যন্তরে থাকা উচিত। ড্রাইভার ছাড়া আর কারওও আইএসআরের সাথে যোগাযোগ করা উচিত নয় - অন্য সব কিছুই স্প্যাগেটি প্রোগ্রামিং।

  • সি লিখার সময়, কোনও আইএসআর এবং পটভূমি প্রোগ্রামের মধ্যে সমস্ত যোগাযোগ অবশ্যই জাতি শর্তের বিরুদ্ধে রক্ষা করা উচিতসর্বদা , প্রতিবার, কোনও ব্যতিক্রম নয়। এমসিইউ ডেটা বাসের আকারটি কিছু যায় আসে না, কারণ আপনি সিতে একটি একক 8 বিট অনুলিপি করলেও ভাষাটি অপারেশনের পারমাণবিকতার গ্যারান্টি দিতে পারে না। আপনি সি 11 বৈশিষ্ট্যটি ব্যবহার না করেই নয় _Atomic। যদি এই বৈশিষ্ট্যটি উপলভ্য না থাকে তবে আপনাকে অবশ্যই সেমাফোড়ের কিছু উপায়ে ব্যবহার করতে হবে বা পড়ার সময় বাধা নিষ্ক্রিয় করতে হবে etc. ইনলাইন এসেম্ব্লার অন্য বিকল্প। volatileপারমাণবিকতা গ্যারান্টি দেয় না।

    যা ঘটতে পারে তা হ'ল -
    রেজিস্টারে স্ট্যাক থেকে
    লোড লোড করুন -অন্তঘাত ঘটে-নিবন্ধক
    থেকে মান ব্যবহার করুন

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


সঠিকভাবে লিখিত এডিসি ড্রাইভারের উদাহরণ এর মতো দেখতে _Atomicপাওয়া যাবে (ধরে নেওয়া সি 11 উপলব্ধ নয়):

adc.h

// adc.h
#ifndef ADC_H
#define ADC_H

/* misc init routines here */

uint16_t adc_get_val (void);

#endif

adc.c

// adc.c
#include "adc.h"

#define ADC0DR (*(volatile uint16_t*)0x1234)

static volatile bool semaphore = false;
static volatile uint16_t adc_val = 0;

uint16_t adc_get_val (void)
{
  uint16_t result;
  semaphore = true;
    result = adc_val;
  semaphore = false;
  return result;
}

interrupt void ADC0_interrupt (void)
{
  if(!semaphore)
  {
    adc_val = ADC0DR;
  }
}
  • এই কোডটি ধরে নিয়েছে যে একটি বিঘ্ন নিজেই বাধা দেওয়া যায় না। এই ধরনের সিস্টেমে, একটি সাধারণ বুলিয়ান সেমফোর হিসাবে কাজ করতে পারে এবং এটি পারমাণবিক হওয়ার দরকার নেই, কারণ বুলেয়ান সেট হওয়ার আগে বাধা উপস্থিত থাকলে কোনও ক্ষতি হয় না। উপরের সরলিকৃত পদ্ধতির নীচের দিকটি হ'ল এটির পরিবর্তে পূর্ববর্তী মানটি ব্যবহার করে যখন জাতি অবস্থার দেখা দেয় তখন এটি ADC রিডগুলি বাতিল করে দেবে। এটি এড়াতেও পারে তবে কোডটি আরও জটিল হয়ে যায় turns

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

  • staticড্রাইভারকে পরিবর্তনশীল স্থানীয় করে স্প্যাগেটি প্রোগ্রামিং এবং নেমস্পেস দূষণের হাত থেকে রক্ষা করে। (এটি একক-কোর, একক থ্রেড অ্যাপ্লিকেশনগুলিতে ভাল তবে মাল্টি-থ্রেডযুক্তগুলিতে নয়))


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

@Arsenal আপনি একটা চমৎকার ডিবাগার যে সি সঙ্গে প্রতীকী ভাষান্তর inlines, এবং আপনি জানেন অন্তত একটি সামান্য বিট এ এস এম থাকে, তাহলে হ্যাঁ এটা করতে সহজ স্পট হও। তবে বৃহত্তর জটিল কোডের জন্য, মেশিন-উত্পাদিত asm এর একটি বিশাল অংশটি অতিক্রম করা তুচ্ছ নয়। বা যদি আপনি asm না জানেন। অথবা যদি আপনার ডিবাগারটি কৃপণ হয় এবং এএসএম না দেখায় (কৌগি ক্লিপসেকফ)।
লন্ডিন

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

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

semaphoreঅবশ্যই হওয়া উচিত volatile! বস্তুত, এটা সবচেয়ে মৌলিক ব্যবহারের ক্ষেত্রে কোনটা আহ্বান অন্য এক মৃত্যুদন্ড প্রসঙ্গ থেকে সংকেত কিছু। - আপনার উদাহরণে, সংকলকটি কেবল বাদ দিতে পারে কারণ এটি 'দেখে' যে এটির ওভাররাইট করার আগে এর মানটি কখনই পড়া হয় না । volatilesemaphore = true;semaphore = false;
জিমিবি

5

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

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

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

সুতরাং আপনার প্রশ্নে ফিরে আসা, যদি আপনার কোডে আরও কিছু থাকে এবং adcValueঅন্য কোডের দ্বারা অ্যাক্সেস হয়ে যায় যা ভিন্ন প্রসঙ্গে চলে, তবে হ্যাঁ,adcValue অস্থির হওয়া উচিত।


4

"গ্লোবাল ভেরিয়েবল যা সরাসরি হার্ডওয়্যার থেকে পরিবর্তিত হয়"

মানটি কিছু হার্ডওয়্যার এডিসি রেজিস্টার থেকে এসেছে বলেই এর অর্থ এই নয় যে এটি হার্ডওয়ার দ্বারা "সরাসরি" পরিবর্তিত হয়েছে।

আপনার উদাহরণস্বরূপ, আপনি কেবল রিডএডিসি () কল করুন, যা কিছু এডিসি রেজিস্টার মান প্রদান করে। সংকলকটির ক্ষেত্রে এটি ঠিক আছে, জেনেও যে অ্যাডক্ল্যাভুকে সেই সময়ে একটি নতুন মান দেওয়া হয়েছে।

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


1
আপনার কোডটি কখনই আইএসআর ফাংশনটিকে "কল" করে না, সংকলক দেখতে পায় যে ভেরিয়েবল কেবল এমন কোনও ফাংশনে আপডেট হয় যা কেউ কল করে না। সুতরাং সংকলক এটি অনুকূলিত করে।
সোয়ানান্দ

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

2
@ ড্যামিয়েন: এটি সর্বদা "নির্ভর" হয়, তবে আমি আসল প্রশ্নটির দিকে লক্ষ্য রাখতে চাইছিলাম "এই ক্ষেত্রে কি কী কীওয়ার্ডটি অস্থির হওয়া উচিত?" যতটা সম্ভব সংক্ষিপ্ত
Rev1.0

4

তর্কটির আচরণটি volatileআপনার কোড, সংকলক এবং অপ্টিমাইজেশনের উপর নির্ভর করে।

দুটি ব্যক্তিগত ব্যবহারের ক্ষেত্র রয়েছে যেখানে আমি ব্যক্তিগতভাবে ব্যবহার করি volatile:

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

  • যদি ভেরিয়েবলটি "কোডের বাইরে" পরিবর্তন হতে পারে তবে সাধারণত আপনার যদি কিছু হার্ডওয়্যার এটি অ্যাক্সেস করে থাকে বা আপনি যদি কোনও ঠিকানায় ভেরিয়েবলটি ম্যাপ করেন তবে।

এম্বেড থাকা অবস্থায়ও অনেক সময় সংকলকগুলিতে বেশ কয়েকটি বাগ থাকে, অপ্টিমাইজেশন করে যা আসলে কাজ করে না, এবং কখনও কখনও volatileসমস্যার সমাধান করতে পারে।

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

উদাহরণ:

void test()
{
    int a = 1;
    printf("%i", a);
}

এই ক্ষেত্রে, পরিবর্তনশীল সম্ভবত মুদ্রণযোগ্য ("% i", 1) এর জন্য অনুকূলিত হবে;

void test()
{
    volatile int a = 1;
    printf("%i", a);
}

অনুকূলিত করা হবে না

আরেকটা:

void delay1Ms()
{
    unsigned int i;
    for (i=0; i<10; i++)
    {
        delay10us( 10);
    }
}

এই ক্ষেত্রে, সংকলক (যদি আপনি গতির জন্য অনুকূলিত হন) এবং এইভাবে ভেরিয়েবলটি ত্যাগ করে উপযুক্ত করতে পারেন

void delay1Ms()
{
       delay10us( 10);
       delay10us( 10);
       delay10us( 10);
       delay10us( 10);
       delay10us( 10);
       delay10us( 10);
       delay10us( 10);
       delay10us( 10);
       delay10us( 10);
       delay10us( 10);
}

আপনার ব্যবহারের ক্ষেত্রে, আপনার অন্য কোডটি কীভাবে adcValueঅন্য কোথাও ব্যবহৃত হচ্ছে এবং আপনি যে সংকলক সংস্করণ / অপ্টিমাইজেশন সেটিংস ব্যবহার করছেন তার উপর "এটি নির্ভর করবে" ।

কখনও কখনও এমন কোনও কোড থাকা বিরক্তিকর হতে পারে যা কোনও অপ্টিমাইজেশন ছাড়াই কাজ করে, তবে একবারে অনুকূলিত হয়ে যায়।

uint16_t adcValue;
void readFromADC(void)
{
  adcValue = readADC();
  printf("%i", adcValue);
}

এটি মুদ্রণযোগ্য ("% i", readADC ()) এ অনুকূলিত হতে পারে;

uint16_t adcValue;
void readFromADC(void)
{
  adcValue = readADC();
  printf("%i", adcValue);
  callAnotherFunction(adcValue);
}

-

uint16_t adcValue;
void readFromADC(void)
{
  adcValue = readADC();
  printf("%i", adcValue);
}

void anotherFunction()
{
   // Do something with adcValue
}

এগুলি সম্ভবত অনুকূলিত করা হবে না তবে আপনি কখনই জানেন না যে "সংকলকটি কতটা ভাল" এবং সংকলক পরামিতিগুলির সাথে পরিবর্তিত হতে পারে। সাধারণত ভাল অপ্টিমাইজেশন সহ সংকলকগুলি লাইসেন্সযুক্ত হয়।


1
উদাহরণস্বরূপ a = 1; খ = একটি; এবং সি = খ; সংকলকটি মনে করতে পারে এক মিনিট অপেক্ষা করুন, a এবং b টি অকেজো, আসুন কেবল 1 থেকে c সরাসরি রেখে দিন। অবশ্যই আপনি নিজের কোডটিতে এটি করবেন না, তবে সংকলকগুলি এটি সন্ধান করার চেয়ে আপনার চেয়ে ভাল, আপনি যদি এখনই অনুকূলিত কোডটি লেখার চেষ্টা করেন তবে এটি অপঠনযোগ্য হবে।
দামিয়েন

2
সঠিক সংকলক সহ একটি সঠিক কোডটি অপ্টিমাইজেশন চালু হওয়ার সাথে ভাঙবে না। সংকলকটির নির্ভুলতা কিছুটা সমস্যা হলেও কমপক্ষে আইএআর-এর সাথে আমি এমন পরিস্থিতির মুখোমুখি হইনি যেখানে অপ্টিমাইজেশানটি ব্রেকিং কোডের দিকে নিয়ে যায় যেখানে এটি হওয়া উচিত নয়।
আর্সেনাল

5
মামলার অনেক যেখানে অপ্টিমাইজেশান কোড ভঙ্গ হয় যখন আপনি ঢোকার হয় UB অঞ্চল খুব ..
নল

2
হ্যাঁ, অস্থির এর একটি পার্শ্ব-প্রতিক্রিয়া হ'ল এটি ডিবাগিংয়ে সহায়তা করতে পারে। তবে এটি অস্থির ব্যবহারের জন্য ভাল কারণ নয়। আপনার সহজেই অপ্টিমাইজেশন বন্ধ করা উচিত যদি সহজ ডিবাগিং আপনার লক্ষ্য হয়। এই উত্তর এমনকি বাধা উল্লেখ করে না।
kkrambo

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

1

প্রচুর প্রযুক্তিগত ব্যাখ্যা কিন্তু আমি ব্যবহারিক প্রয়োগটিতে মনোনিবেশ করতে চাই।

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

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

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

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

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


0

কোনও যোগ্যতার অনুপস্থিতিতে volatileকোডের কিছু অংশের সময় কোনও জিনিসের মান একাধিক স্থানে সংরক্ষণ করা যেতে পারে। উদাহরণস্বরূপ, এরকম কিছু দেওয়া বিবেচনা করুন:

int foo;
int someArray[64];
void test(void)
{
  int i;
  foo = 0;
  for (i=0; i<64; i++)
    if (someArray[i] > 0)
      foo++;
}

সি এর প্রথম দিনগুলিতে, একটি সংকলক বিবৃতিটি প্রক্রিয়া করত

foo++;

পদক্ষেপের মাধ্যমে:

load foo into a register
increment that register
store that register back to foo

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

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

কিছু সংকলক লেখক এবং প্রোগ্রামারদের মধ্যে দ্বন্দ্বের কিছুটা ঘটনার সাথে ঘটে:

unsigned short volatile *volatile output_ptr;
unsigned volatile output_count;

void interrupt_handler(void)
{
  if (output_count)
  {
    *((unsigned short*)0xC0001230) = *output_ptr; // Hardware I/O register
    *((unsigned short*)0xC0001234) = 1; // Hardware I/O register
    *((unsigned short*)0xC0001234) = 0; // Hardware I/O register
    output_ptr++;
    output_count--;
  }
}

void output_data_via_interrupt(unsigned short *dat, unsigned count)
{
  output_ptr = dat;
  output_count = count;
  while(output_count)
     ; // Wait for interrupt to output the data
}

unsigned short output_buffer[10];

void test(void)
{
  output_buffer[0] = 0x1234;
  output_data_via_interrupt(output_buffer, 1);
  output_buffer[0] = 0x2345;
  output_buffer[1] = 0x6789;
  output_data_via_interrupt(output_buffer,2);
}

Icallyতিহাসিকভাবে, বেশিরভাগ সংকলকরা হয় সম্ভাবনার পক্ষে মঞ্জুরি দেয় যে কোনও volatileস্টোরেজ লোকেশন লিখে ইচ্ছামত পার্শ্ব-প্রতিক্রিয়া সৃষ্টি করতে পারে, এবং এই জাতীয় স্টোরের রেজিস্টারে কোনও মান ক্যাচ করা এড়াতে পারে, অথবা অন্যথায় তারা ফাংশনগুলিতে কলগুলিতে রেজিস্টারগুলিতে মানগুলি ক্যাচ করা থেকে বিরত থাকবে are যোগ্য নয় "ইনলাইন", এবং এভাবে 0x1234 লিখবেন output_buffer[0], তথ্য আউটপুট দেওয়ার জন্য জিনিসগুলি সেট আপ করবেন, এটি সম্পন্ন হওয়ার জন্য অপেক্ষা করুন, তারপরে 0x2345 লিখুন output_buffer[0]এবং সেখান থেকে চালিয়ে যান। স্ট্যান্ডার্ডের প্রয়োজন হয় নাঠিকানাটি সংরক্ষণ করার আইনটির জন্য বাস্তবায়নoutput_buffer একটি মধ্যেvolatileযোগ্য পয়েন্টারটি একটি চিহ্ন হিসাবে যে এর মাধ্যমে কিছু ঘটতে পারে তার অর্থ সংকলক বুঝতে পারে না, তবে লেখকরা ভেবেছিলেন যে বিভিন্ন প্ল্যাটফর্ম এবং উদ্দেশ্যগুলির উদ্দেশ্যে রচনা করা সংকলকগুলির লেখকগণ যখন এটি করার সময় সেই প্ল্যাটফর্মগুলিতে সেই উদ্দেশ্যগুলি পরিবেশন করবে তখন তারা বুঝতে পারে comp না বলা ছাড়া। ফলস্বরূপ, কিছু "চালাক" সংকলক যেমন জিসিসি এবং ক্ল্যাংগুলি ধরে নেবে যে ঠিকানার ঠিকানাটি output_bufferদুটি স্টোরের মধ্যে একটি অস্থির-যোগ্য পয়েন্টারকে লেখা হয়েছে output_buffer[0], তবে এটি ধরে নেওয়ার কোনও কারণ নেই যে সেই বস্তুটিতে থাকা মূল্য সম্পর্কে কোনও কিছু যত্নশীল হতে পারে ume ঐ সময়.

তদ্ব্যতীত, নির্দেশকগুলি যা সরাসরি পূর্ণসংখ্যার কাছ থেকে কাস্ট করা হয় সেগুলি কমপ্লায়াররা বুঝতে না পারে এমন উপায়ে জিনিসগুলি চালিত করা ব্যতীত অন্য কোনও উদ্দেশ্যে খুব কমই ব্যবহৃত হয়, তবে স্ট্যান্ডার্ডটিকে আবার এরূপ অ্যাক্সেসগুলি চিকিত্সার জন্য কম্পাইলারগুলির প্রয়োজন হয় না volatile। ফলস্বরূপ, প্রথম লেখার জন্য *((unsigned short*)0xC0001234)জিসিসি এবং ক্ল্যাংয়ের মতো "চতুর" সংকলক বাদ দিতে পারে, কারণ এই ধরনের সংকলকগুলির রক্ষণাবেক্ষণকারীরা বরং সেই কোডটিকে দাবী করবে যা volatile"ভাঙা" জাতীয় বিষয়গুলির যোগ্যতার তুলনায় অবহেলা করে যা এই কোডটির সাথে সঙ্গতিযোগ্যতা স্বীকৃত হওয়ার চেয়ে স্বীকৃতি দেয় । প্রচুর বিক্রেতার সরবরাহকৃত শিরোলেখ ফাইলগুলি volatileকোয়ালিফায়ার বাদ দেয় এবং একটি সংকলক যা বিক্রেতার সরবরাহকৃত শিরোলেখ ফাইলগুলির সাথে সামঞ্জস্যপূর্ণ তার চেয়ে বেশি কার্যকর।

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