தமிழ்

பூட்டு இல்லா நிரலாக்கத்தின் அடிப்படைகளையும், அணுநிலை செயல்பாடுகளையும் ஆராயுங்கள். உயர் செயல்திறன் அமைப்புகளுக்கு அவற்றின் முக்கியத்துவத்தை உலகளாவிய எடுத்துக்காட்டுகளுடன் டெவலப்பர்கள் அறிந்து கொள்ளலாம்.

பூட்டு இல்லா நிரலாக்கத்தை தெளிவுபடுத்துதல்: உலகளாவிய உருவாக்குநர்களுக்கான அணுநிலை செயல்பாடுகளின் சக்தி

இன்றைய ஒன்றோடொன்று இணைக்கப்பட்ட டிஜிட்டல் உலகில், செயல்திறன் மற்றும் அளவிடுதல் தன்மை ஆகியவை மிக முக்கியமானவை. பயன்பாடுகள் அதிகரிக்கும் சுமைகளையும் சிக்கலான கணக்கீடுகளையும் கையாளும் வகையில் உருவாகும்போது, மியூடெக்ஸ்கள் மற்றும் செமாஃபோர்கள் போன்ற பாரம்பரிய ஒத்திசைவு வழிமுறைகள் இடையூறுகளாக மாறக்கூடும். இங்குதான் பூட்டு இல்லா நிரலாக்கம் ஒரு சக்திவாய்ந்த முன்னுதாரணமாக உருவெடுக்கிறது, இது மிகவும் திறமையான மற்றும் பதிலளிக்கக்கூடிய ஒரே நேரத்தில் இயங்கும் அமைப்புகளுக்கான ஒரு வழியை வழங்குகிறது. பூட்டு இல்லா நிரலாக்கத்தின் மையத்தில் ஒரு அடிப்படைக் கருத்து உள்ளது: அணுநிலை செயல்பாடுகள். இந்த விரிவான வழிகாட்டி பூட்டு இல்லா நிரலாக்கத்தையும், உலகெங்கிலும் உள்ள உருவாக்குநர்களுக்கான அணுநிலை செயல்பாடுகளின் முக்கிய பங்கையும் தெளிவுபடுத்தும்.

பூட்டு இல்லா நிரலாக்கம் என்றால் என்ன?

பூட்டு இல்லா நிரலாக்கம் என்பது ஒரு உடன் நிகழ்வு கட்டுப்பாட்டு உத்தியாகும், இது அமைப்பு தழுவிய முன்னேற்றத்திற்கு உத்தரவாதம் அளிக்கிறது. ஒரு பூட்டு இல்லா அமைப்பில், மற்ற திரிக்கள் (threads) தாமதமானாலும் அல்லது இடைநிறுத்தப்பட்டாலும், குறைந்தபட்சம் ஒரு திரியாவது எப்போதும் முன்னேற்றம் அடையும். இது பூட்டு அடிப்படையிலான அமைப்புகளுக்கு முரணானது, அங்கு ஒரு பூட்டை வைத்திருக்கும் திரி இடைநிறுத்தப்படலாம், அந்தப் பூட்டு தேவைப்படும் வேறு எந்த திரியையும் தொடரவிடாமல் தடுக்கிறது. இது முட்டுக்கட்டைகள் (deadlocks) அல்லது உயிருள்ள முட்டுக்கட்டைகளுக்கு (livelocks) வழிவகுக்கும், இது பயன்பாட்டின் பதிலளிப்புத் தன்மையை கடுமையாக பாதிக்கும்.

பூட்டு இல்லா நிரலாக்கத்தின் முதன்மை நோக்கம், பாரம்பரிய பூட்டுதல் வழிமுறைகளுடன் தொடர்புடைய போட்டி மற்றும் சாத்தியமான தடுத்தலைத் தவிர்ப்பதாகும். பகிரப்பட்ட தரவுகளில் வெளிப்படையான பூட்டுகள் இல்லாமல் செயல்படும் வழிமுறைகளை கவனமாக வடிவமைப்பதன் மூலம், உருவாக்குநர்கள் பின்வருவனவற்றை அடையலாம்:

மூலைக்கல்: அணுநிலை செயல்பாடுகள்

அணுநிலை செயல்பாடுகள் பூட்டு இல்லா நிரலாக்கத்தின் அடித்தளமாகும். ஒரு அணுநிலை செயல்பாடு என்பது ஒரு செயல்பாடு குறுக்கீடு இல்லாமல் முழுமையாக செயல்படுத்தப்படும் அல்லது செயல்படுத்தப்படாது என்பதற்கு உத்தரவாதம் அளிப்பதாகும். மற்ற திரிக்களின் கண்ணோட்டத்தில், ஒரு அணுநிலை செயல்பாடு உடனடியாக நடப்பதாகத் தோன்றும். பல திரிக்கள் ஒரே நேரத்தில் பகிரப்பட்ட தரவை அணுகி மாற்றும்போது தரவு நிலைத்தன்மையைப் பராமரிக்க இந்த பிரிக்க முடியாத தன்மை முக்கியமானது.

இதை இப்படி யோசித்துப் பாருங்கள்: நீங்கள் ஒரு எண்ணை நினைவகத்தில் எழுதினால், ஒரு அணுநிலை எழுத்து அந்த முழு எண்ணும் எழுதப்படுவதை உறுதி செய்கிறது. ஒரு அணுநிலை அல்லாத எழுத்து பாதியில் குறுக்கிடப்படலாம், இது பகுதியளவு எழுதப்பட்ட, சிதைந்த மதிப்பை விட்டுச்செல்லும், அதை மற்ற திரிக்கள் படிக்கக்கூடும். அணுநிலை செயல்பாடுகள் அத்தகைய பந்தய நிலைகளை (race conditions) மிகக் குறைந்த மட்டத்தில் தடுக்கின்றன.

பொதுவான அணுநிலை செயல்பாடுகள்

வன்பொருள் கட்டமைப்புகள் மற்றும் நிரலாக்க மொழிகளில் அணுநிலை செயல்பாடுகளின் குறிப்பிட்ட தொகுப்பு மாறுபடலாம் என்றாலும், சில அடிப்படை செயல்பாடுகள் பரவலாக ஆதரிக்கப்படுகின்றன:

பூட்டு இல்லா நிரலாக்கத்திற்கு அணுநிலை செயல்பாடுகள் ஏன் அவசியம்?

பூட்டு இல்லா வழிமுறைகள் பாரம்பரிய பூட்டுகள் இல்லாமல் பகிரப்பட்ட தரவை பாதுகாப்பாகக் கையாள அணுநிலை செயல்பாடுகளை நம்பியுள்ளன. ஒப்பிட்டு-மாற்று (CAS) செயல்பாடு குறிப்பாக முக்கியமானது. பல திரிக்கள் ஒரு பகிரப்பட்ட எண்ணியைப் புதுப்பிக்க வேண்டிய ஒரு சூழ்நிலையைக் கவனியுங்கள். ஒரு எளிய அணுகுமுறை எண்ணியைப் படிப்பது, அதை அதிகரிப்பது, மற்றும் அதை மீண்டும் எழுதுவதை உள்ளடக்கியிருக்கலாம். இந்த வரிசை பந்தய நிலைகளுக்கு ஆளாக நேரிடும்:

// அணுநிலை அல்லாத அதிகரிப்பு (பந்தய நிலைகளால் பாதிக்கப்படக்கூடியது)
int counter = shared_variable;
counter++;
shared_variable = counter;

திரி A மதிப்பு 5-ஐப் படித்து, அது 6-ஐ மீண்டும் எழுதுவதற்கு முன்பு, திரி B-யும் 5-ஐப் படித்து, அதை 6 ஆக அதிகரித்து, 6-ஐ மீண்டும் எழுதினால், திரி A பின்னர் 6-ஐ மீண்டும் எழுதும், இது திரி B-யின் புதுப்பிப்பை மேலெழுதும். எண்ணி 7 ஆக இருக்க வேண்டும், ஆனால் அது 6 மட்டுமே.

CAS-ஐப் பயன்படுத்தி, செயல்பாடு இவ்வாறு ஆகிறது:

// CAS பயன்படுத்தி அணுநிலை அதிகரிப்பு
int expected_value = shared_variable.load();
int new_value;

do {
    new_value = expected_value + 1;
} while (!shared_variable.compare_exchange_weak(expected_value, new_value));

இந்த CAS-அடிப்படையிலான அணுகுமுறையில்:

  1. திரி தற்போதைய மதிப்பை (`expected_value`) படிக்கிறது.
  2. அது `new_value`-ஐக் கணக்கிடுகிறது.
  3. `shared_variable`-இல் உள்ள மதிப்பு இன்னும் `expected_value` ஆக இருந்தால் மட்டும், `expected_value`-ஐ `new_value`-உடன் மாற்ற முயற்சிக்கிறது.
  4. மாற்றுதல் வெற்றி பெற்றால், செயல்பாடு முடிந்தது.
  5. மாற்றுதல் தோல்வியுற்றால் (ஏனெனில் மற்றொரு திரி `shared_variable`-ஐ இடையில் மாற்றிவிட்டது), `expected_value` ஆனது `shared_variable`-இன் தற்போதைய மதிப்புடன் புதுப்பிக்கப்பட்டு, சுழற்சி CAS செயல்பாட்டை மீண்டும் முயற்சிக்கிறது.

இந்த மீண்டும் முயற்சிக்கும் சுழற்சி, அதிகரிப்பு செயல்பாடு இறுதியில் வெற்றிபெறுவதை உறுதி செய்கிறது, இது ஒரு பூட்டு இல்லாமல் முன்னேற்றத்திற்கு உத்தரவாதம் அளிக்கிறது. `compare_exchange_weak` (C++ இல் பொதுவானது) பயன்பாடு ஒரு செயல்பாட்டிற்குள் பலமுறை சரிபார்ப்பைச் செய்யலாம், ஆனால் சில கட்டமைப்புகளில் இது மிகவும் திறமையானதாக இருக்கும். ஒரு பாஸில் முழுமையான உறுதியைப் பெற, `compare_exchange_strong` பயன்படுத்தப்படுகிறது.

பூட்டு இல்லா பண்புகளை அடைதல்

உண்மையிலேயே பூட்டு இல்லா என்று கருதப்பட, ஒரு வழிமுறை பின்வரும் நிபந்தனையை பூர்த்தி செய்ய வேண்டும்:

இத்துடன் தொடர்புடைய காத்திருப்பு இல்லா நிரலாக்கம் (wait-free programming) என்ற ஒரு கருத்தும் உள்ளது, இது இன்னும் வலிமையானது. ஒரு காத்திருப்பு இல்லா வழிமுறை, மற்ற திரிக்களின் நிலையைப் பொருட்படுத்தாமல், ஒவ்வொரு திரியும் அதன் செயல்பாட்டை ஒரு குறிப்பிட்ட எண்ணிக்கையிலான படிகளில் முடிக்கும் என்று உத்தரவாதம் அளிக்கிறது. இது சிறந்தது என்றாலும், காத்திருப்பு இல்லா வழிமுறைகளை வடிவமைப்பதும் செயல்படுத்துவதும் பெரும்பாலும் மிகவும் சிக்கலானவை.

பூட்டு இல்லா நிரலாக்கத்தில் உள்ள சவால்கள்

நன்மைகள் கணிசமானவை என்றாலும், பூட்டு இல்லா நிரலாக்கம் ஒரு வெள்ளித் குண்டு அல்ல, அது அதன் சொந்த சவால்களுடன் வருகிறது:

1. சிக்கலான தன்மை மற்றும் சரித்தன்மை

சரியான பூட்டு இல்லா வழிமுறைகளை வடிவமைப்பது மிகவும் கடினம். இதற்கு நினைவக மாதிரிகள், அணுநிலை செயல்பாடுகள் மற்றும் அனுபவமுள்ள உருவாக்குநர்கள் கூட கவனிக்கத் தவறும் நுட்பமான பந்தய நிலைகள் பற்றிய ஆழமான புரிதல் தேவை. பூட்டு இல்லா குறியீட்டின் சரித்தன்மையை நிரூபிப்பது பெரும்பாலும் முறையான முறைகள் அல்லது கடுமையான சோதனைகளை உள்ளடக்கியது.

2. ABA சிக்கல்

ABA சிக்கல் என்பது பூட்டு இல்லா தரவுக் கட்டமைப்புகளில், குறிப்பாக CAS-ஐப் பயன்படுத்தும் கட்டமைப்புகளில் ஒரு பொதுவான சவாலாகும். ஒரு மதிப்பு படிக்கப்படும்போது (A), பின்னர் மற்றொரு திரியால் B ஆக மாற்றப்பட்டு, முதல் திரி அதன் CAS செயல்பாட்டைச் செய்வதற்கு முன்பு மீண்டும் A ஆக மாற்றப்படும்போது இது நிகழ்கிறது. மதிப்பு A என்பதால் CAS செயல்பாடு வெற்றி பெறும், ஆனால் முதல் வாசிப்பிற்கும் CAS-க்கும் இடையிலான தரவு குறிப்பிடத்தக்க மாற்றங்களுக்கு உள்ளாகியிருக்கலாம், இது தவறான நடத்தைக்கு வழிவகுக்கும்.

எடுத்துக்காட்டு:

  1. திரி 1, பகிரப்பட்ட மாறியிலிருந்து A என்ற மதிப்பைப் படிக்கிறது.
  2. திரி 2, மதிப்பை B ஆக மாற்றுகிறது.
  3. திரி 2, மதிப்பை மீண்டும் A ஆக மாற்றுகிறது.
  4. திரி 1, அசல் மதிப்பு A உடன் CAS-ஐ முயற்சிக்கிறது. மதிப்பு இன்னும் A என்பதால் CAS வெற்றி பெறுகிறது, ஆனால் திரி 2 செய்த இடைப்பட்ட மாற்றங்கள் (திரி 1 அறியாதது) செயல்பாட்டின் அனுமானங்களை செல்லாததாக்கக்கூடும்.

ABA சிக்கலுக்கான தீர்வுகள் பொதுவாக குறிச்சொல் சுட்டிகள் (tagged pointers) அல்லது பதிப்பு எண்ணிகளை (version counters) பயன்படுத்துவதை உள்ளடக்கியது. ஒரு குறிச்சொல் சுட்டி ஒரு பதிப்பு எண்ணை (குறிச்சொல்) சுட்டியுடன் இணைக்கிறது. ஒவ்வொரு மாற்றமும் குறிச்சொல்லை அதிகரிக்கிறது. CAS செயல்பாடுகள் பின்னர் சுட்டி மற்றும் குறிச்சொல் இரண்டையும் சரிபார்க்கின்றன, இது ABA சிக்கல் ஏற்படுவதை மிகவும் கடினமாக்குகிறது.

3. நினைவக மேலாண்மை

C++ போன்ற மொழிகளில், பூட்டு இல்லா கட்டமைப்புகளில் கைமுறை நினைவக மேலாண்மை மேலும் சிக்கலை அறிமுகப்படுத்துகிறது. ஒரு பூட்டு இல்லா இணைக்கப்பட்ட பட்டியலில் (linked list) ஒரு நோட் தர்க்கரீதியாக அகற்றப்படும்போது, அதை உடனடியாக விடுவிக்க முடியாது, ஏனெனில் மற்ற திரிக்கள் தர்க்கரீதியாக அகற்றப்படுவதற்கு முன்பு அதற்கான ஒரு சுட்டியைப் படித்திருக்கலாம், இன்னும் அதில் செயல்பட்டுக் கொண்டிருக்கலாம். இதற்கு மேம்பட்ட நினைவக மீட்பு நுட்பங்கள் தேவை:

குப்பை சேகரிப்பு (garbage collection) உள்ள ஜாவா அல்லது C# போன்ற நிர்வகிக்கப்பட்ட மொழிகள் நினைவக மேலாண்மையை எளிதாக்கலாம், ஆனால் அவை குப்பை சேகரிப்பு இடைநிறுத்தங்கள் மற்றும் பூட்டு இல்லா உத்தரவாதங்களில் அவற்றின் தாக்கம் தொடர்பான சொந்த சிக்கல்களை அறிமுகப்படுத்துகின்றன.

4. செயல்திறன் முன்கணிப்பு

பூட்டு இல்லா நிரலாக்கம் சிறந்த சராசரி செயல்திறனை வழங்க முடியும் என்றாலும், CAS சுழற்சிகளில் மீண்டும் முயற்சிகள் காரணமாக தனிப்பட்ட செயல்பாடுகள் அதிக நேரம் எடுக்கலாம். இது பூட்டு அடிப்படையிலான அணுகுமுறைகளுடன் ஒப்பிடும்போது செயல்திறனை குறைவாக முன்கணிக்கக்கூடியதாக மாற்றும், அங்கு ஒரு பூட்டுக்கான அதிகபட்ச காத்திருப்பு நேரம் பெரும்பாலும் வரையறுக்கப்பட்டுள்ளது (முட்டுக்கட்டைகள் ஏற்பட்டால் வரம்பற்றதாக இருந்தாலும்).

5. பிழைதிருத்தம் மற்றும் கருவிகள்

பூட்டு இல்லா குறியீட்டை பிழைதிருத்தம் செய்வது கணிசமாக கடினமானது. நிலையான பிழைதிருத்த கருவிகள் அணுநிலை செயல்பாடுகளின் போது அமைப்பின் நிலையை துல்லியமாக பிரதிபலிக்காது, மேலும் செயல்பாட்டின் ஓட்டத்தை காட்சிப்படுத்துவது சவாலானதாக இருக்கும்.

பூட்டு இல்லா நிரலாக்கம் எங்கே பயன்படுத்தப்படுகிறது?

சில களங்களின் கோரும் செயல்திறன் மற்றும் அளவிடுதல் தேவைகள் பூட்டு இல்லா நிரலாக்கத்தை ஒரு தவிர்க்க முடியாத கருவியாக ஆக்குகின்றன. உலகளாவிய எடுத்துக்காட்டுகள் ஏராளமாக உள்ளன:

பூட்டு இல்லா கட்டமைப்புகளை செயல்படுத்துதல்: ஒரு நடைமுறை எடுத்துக்காட்டு (கருத்துரு)

CAS-ஐப் பயன்படுத்தி செயல்படுத்தப்பட்ட ஒரு எளிய பூட்டு இல்லா ஸ்டேக்கை (stack) கருத்தில் கொள்வோம். ஒரு ஸ்டேக் பொதுவாக `push` மற்றும் `pop` போன்ற செயல்பாடுகளைக் கொண்டுள்ளது.

தரவுக் கட்டமைப்பு:

struct Node {
    Value data;
    Node* next;
};

class LockFreeStack {
private:
    std::atomic head;

public:
    void push(Value val) {
        Node* newNode = new Node{val, nullptr};
        Node* oldHead;
        do {
            oldHead = head.load(); // தற்போதைய head-ஐ அணுநிலையில் படிக்கவும்
            newNode->next = oldHead;
            // head மாறவில்லை என்றால், புதிய head-ஐ அமைக்க அணுநிலையில் முயற்சிக்கவும்
        } while (!head.compare_exchange_weak(oldHead, newNode));
    }

    Value pop() {
        Node* oldHead;
        Value val;
        do {
            oldHead = head.load(); // தற்போதைய head-ஐ அணுநிலையில் படிக்கவும்
            if (!oldHead) {
                // ஸ்டாக் காலியாக உள்ளது, தகுந்த முறையில் கையாளவும் (எ.கா., விதிவிலக்கு வீசுதல் அல்லது சென்டினல் திருப்புதல்)
                throw std::runtime_error("Stack underflow");
            }
            // தற்போதைய head-ஐ அடுத்த நோடின் சுட்டியுடன் மாற்ற முயற்சிக்கவும்
            // வெற்றி பெற்றால், oldHead ஆனது pop செய்யப்பட்ட நோடைச் சுட்டும்
        } while (!head.compare_exchange_weak(oldHead, oldHead->next));

        val = oldHead->data;
        // சிக்கல்: ABA அல்லது use-after-free இல்லாமல் oldHead-ஐ பாதுகாப்பாக நீக்குவது எப்படி?
        // இங்கேதான் மேம்பட்ட நினைவக மீட்பு தேவைப்படுகிறது.
        // விளக்கத்திற்காக, பாதுகாப்பான நீக்குதலைத் தவிர்ப்போம்.
        // delete oldHead; // உண்மையான மல்டித்ரெட் சூழலில் பாதுகாப்பற்றது!
        return val;
    }
};

`push` செயல்பாட்டில்:

  1. ஒரு புதிய `Node` உருவாக்கப்படுகிறது.
  2. தற்போதைய `head` அணுநிலையில் படிக்கப்படுகிறது.
  3. புதிய நோடின் `next` சுட்டி `oldHead`-க்கு அமைக்கப்படுகிறது.
  4. `head`-ஐ `newNode`-ஐச் சுட்டிக்காட்ட ஒரு CAS செயல்பாடு முயற்சிக்கிறது. `load` மற்றும் `compare_exchange_weak` அழைப்புகளுக்கு இடையில் `head` மற்றொரு திரியால் மாற்றப்பட்டிருந்தால், CAS தோல்வியடைகிறது, மற்றும் சுழற்சி மீண்டும் முயற்சிக்கிறது.

`pop` செயல்பாட்டில்:

  1. தற்போதைய `head` அணுநிலையில் படிக்கப்படுகிறது.
  2. ஸ்டாக் காலியாக இருந்தால் (`oldHead` null ஆக இருந்தால்), ஒரு பிழை சமிக்ஞை செய்யப்படுகிறது.
  3. `head`-ஐ `oldHead->next`-ஐச் சுட்டிக்காட்ட ஒரு CAS செயல்பாடு முயற்சிக்கிறது. `head` மற்றொரு திரியால் மாற்றப்பட்டிருந்தால், CAS தோல்வியடைகிறது, மற்றும் சுழற்சி மீண்டும் முயற்சிக்கிறது.
  4. CAS வெற்றி பெற்றால், `oldHead` இப்போது ஸ்டேக்கிலிருந்து அகற்றப்பட்ட நோடைச் சுட்டுகிறது. அதன் தரவு மீட்டெடுக்கப்படுகிறது.

இங்கே விடுபட்ட முக்கியமான பகுதி `oldHead`-இன் பாதுகாப்பான நீக்கம் ஆகும். முன்பே குறிப்பிட்டது போல, இது அபாயச் சுட்டிகள் அல்லது யுகம்-அடிப்படையிலான மீட்பு போன்ற மேம்பட்ட நினைவக மேலாண்மை நுட்பங்களைக் கோருகிறது, இது கைமுறை நினைவக மேலாண்மை பூட்டு இல்லா கட்டமைப்புகளில் ஒரு பெரிய சவாலாகும்.

சரியான அணுகுமுறையைத் தேர்ந்தெடுத்தல்: பூட்டுகள் மற்றும் பூட்டு இல்லா

பூட்டு இல்லா நிரலாக்கத்தைப் பயன்படுத்தும் முடிவு பயன்பாட்டின் தேவைகளை கவனமாக பகுப்பாய்வு செய்வதன் அடிப்படையில் இருக்க வேண்டும்:

பூட்டு இல்லா மேம்பாட்டிற்கான சிறந்த நடைமுறைகள்

பூட்டு இல்லா நிரலாக்கத்தில் நுழையும் உருவாக்குநர்களுக்கு, இந்த சிறந்த நடைமுறைகளைக் கருத்தில் கொள்ளுங்கள்:

முடிவுரை

அணுநிலை செயல்பாடுகளால் இயக்கப்படும் பூட்டு இல்லா நிரலாக்கம், உயர் செயல்திறன், அளவிடக்கூடிய மற்றும் மீள்தன்மையுடைய உடன் நிகழ்வு அமைப்புகளை உருவாக்குவதற்கான ஒரு மேம்பட்ட அணுகுமுறையை வழங்குகிறது. இது கணினி கட்டமைப்பு மற்றும் உடன் நிகழ்வு கட்டுப்பாடு பற்றிய ஆழமான புரிதலைக் கோரினாலும், தாமத-உணர்திறன் மற்றும் அதிக-போட்டி சூழல்களில் அதன் நன்மைகள் மறுக்க முடியாதவை. அதிநவீன பயன்பாடுகளில் பணிபுரியும் உலகளாவிய உருவாக்குநர்களுக்கு, அணுநிலை செயல்பாடுகள் மற்றும் பூட்டு இல்லா வடிவமைப்பின் கொள்கைகளில் தேர்ச்சி பெறுவது ஒரு குறிப்பிடத்தக்க வேறுபாடாக இருக்க முடியும், இது பெருகிய முறையில் இணையாக இயங்கும் உலகின் கோரிக்கைகளைப் பூர்த்தி செய்யும் மிகவும் திறமையான மற்றும் வலுவான மென்பொருள் தீர்வுகளை உருவாக்க உதவுகிறது.