थ्रेड-लोकल स्टोरेज

From Vigyanwiki


कंप्यूटर प्रोग्रामिंग में, थ्रेड-लोकल स्टोरेज (TLS) एक मेमोरी मैनेजमेंट मेथड है जो स्थैतिक मेमोरी या ग्लोबल कंप्यूटर स्टोरेज को थ्रेड (कंप्यूटिंग) के लिए लोकल का उपयोग करता है।

जबकि आधुनिक प्रोग्रामिंग में ग्लोबल वेरिएबल के उपयोग को समान्यत: हतोत्साहित किया जाता है, यूनिक्स जैसे लीगेसी ऑपरेटिंग सिस्टम को यूनिप्रोसेसर हार्डवेयर के लिए डिज़ाइन किया गया है और प्री-रीएंट्रेंसी (कंप्यूटिंग) एपीआई के शब्दार्थ को बनाए रखने के लिए कुछ अतिरिक्त तंत्र की आवश्यकता होती है। ऐसी स्थितियों का एक उदाहरण है जहां फ़ंक्शन त्रुटि स्थिति सेट करने के लिए ग्लोबल वेरिएबल का उपयोग करते हैं (उदाहरण के लिए ग्लोबल वेरिएबल errno c लाइब्रेरी के कई कार्यों द्वारा उपयोग किया जाता है)। यदि errno एक ग्लोबल वेरिएबल थे, एक थ्रेड पर एक सिस्टम फ़ंक्शन की कॉल किसी भिन्न थ्रेड पर सिस्टम फ़ंक्शन के कॉल द्वारा पहले सेट किए गए मान को अधिलेखित कर सकती है, संभवत: उस भिन्न थ्रेड पर कोड का पालन करने से पहले त्रुटि स्थिति की जांच कर सकती है। जिसका समाधान होना है errno ऐसा वेरिएबल हो जो ऐसा लगता है कि यह ग्लोबल है, किंतु वास्तव में प्रति थ्रेड एक बार उपस्थित है- अथार्त यह थ्रेड-लोकल स्टोरेज में रहता है। एक दूसरा उपयोग स्थिति एक ग्लोबल वेरिएबल में जानकारी जमा करने वाले कई सूत्र होंगे। रेस कंडीशन से बचने के लिए, इस ग्लोबल वेरिएबल की प्रत्येक पहुंच को एक लॉक (कंप्यूटर विज्ञान) द्वारा संरक्षित करना होगा। वैकल्पिक रूप से, प्रत्येक थ्रेड एक थ्रेड-लोकल वेरिएबल में जमा हो सकता है (जो कि, परिलैंग्वेज के अनुसार, अन्य थ्रेड्स से पढ़ा या लिखा नहीं जा सकता है, जिसका अर्थ है कि रेस कंडीशन नहीं हो सकती है)। थ्रेड्स को केवल अपने स्वयं के थ्रेड-स्थानीय वेरिएबल से एक एकल, सही विधि में ग्लोबल वेरिएबल में अंतिम संचय को सिंक्रनाइज़ करना होगा।

कई प्रणालियाँ थ्रेड-लोकल मेमोरी ब्लॉक के आकार पर प्रतिबंध लगाती हैं, वास्तव में अधिकांशतः किंतु तंग सीमाएँ दूसरी ओर, यदि कोई सिस्टम कम से कम एक मेमोरी एड्रेस (पॉइंटर) आकार का वेरिएबल थ्रेड-लोकल प्रदान कर सकता है, तो यह इच्छित रूप से आकार के मेमोरी ब्लॉक को थ्रेड-लोकल विधि से उपयोग करने की अनुमति देता है, इस तरह के मेमोरी ब्लॉक को गतिशील रूप से आवंटित करके और स्टोर करके थ्रेड-लोकल वैरिएबल में उस ब्लॉक का मेमोरी एड्रेस कम निर्देश सेट कंप्यूटर मशीनों पर, कॉलिंग कन्वेंशन अधिकांशतः इस उपयोग के लिए थ्रेड पॉइंटर रजिस्टर आरक्षित करता है।

विंडोज कार्यान्वयन

एप्लिकेशन प्रोग्रामिंग इंटरफ़ेस (एपीआई) फ़ंक्शन TlsAlloc का उपयोग अप्रयुक्त टीएलएस स्लॉट इंडेक्स प्राप्त करने के लिए किया जा सकता है; टीएलएस स्लॉट इंडेक्स को तब 'प्रयुक्त' माना जाएगा।

TlsGetValue और TlsSetValue फ़ंक्शंस का उपयोग टीएलएस स्लॉट इंडेक्स द्वारा पहचाने गए थ्रेड-लोकल वेरिएबल में मेमोरी एड्रेस को पढ़ने और लिखने के लिए किया जाता है। TlsSetValue केवल वर्तमान थ्रेड के वेरिएबल को प्रभावित करता है। टीएलएस स्लॉट इंडेक्स जारी करने के लिए TlsFree फ़ंक्शन को कॉल किया जा सकता है।

प्रत्येक थ्रेड के लिए एक विन32 थ्रेड सूचना ब्लॉक है। इस ब्लॉक में प्रविष्टियों में से एक उस थ्रेड के लिए थ्रेड-लोकल स्टोरेज टेबल है।[1] TlsAlloc प्रत्येक कॉल के लिए इस तालिका में एक अनुक्रमणिका लौटाता है, अद्वितीय प्रति एड्रेस स्थान प्रत्येक थ्रेड के पास थ्रेड-लोकल स्टोरेज टेबल की अपनी कॉपी होती है। इसलिए, प्रत्येक थ्रेड स्वतंत्र रूप से TlsSetValue(index) का उपयोग कर सकता है और TlsGetValue(index) के माध्यम से निर्दिष्ट मान प्राप्त कर सकता है, क्योंकि ये थ्रेड की अपनी तालिका में एक प्रविष्टि सेट और खोजते हैं।

TlsXxx ​​फ़ंक्शन वर्ग के अतिरिक्त, विंडोज़ एक्जीक्यूटेबल्स एक सेक्शन को परिभाषित कर सकते हैं जो निष्पादन प्रक्रिया के प्रत्येक थ्रेड के लिए एक अलग पृष्ठ पर मैप किया गया है। TlsXxx ​​मानों के विपरीत, इन पृष्ठों में इच्छित और वैध पते हो सकते हैं। चूँकि ये पते प्रत्येक निष्पादन थ्रेड के लिए अलग-अलग हैं और इसलिए एसिंक्रोनस फ़ंक्शंस (जो एक अलग थ्रेड में निष्पादित हो सकते हैं) या अन्यथा कोड को पास नहीं किया जाना चाहिए, जो मानते हैं कि पूरी प्रक्रिया के अंदर एक वर्चुअल एड्रेस अद्वितीय है। टीएलएस अनुभागों को पेजिंग का उपयोग करके प्रबंधित किया जाता है और इसका आकार पृष्ठ आकार (x86 मशीनों पर 4kB) तक निर्धारित किया जाता है। इस तरह के अनुभागों को केवल एक प्रोग्राम के मुख्य निष्पादन योग्य के अंदर परिभाषित किया जा सकता है - डायनामिक-लिंक लाइब्रेरी में ऐसे अनुभाग नहीं होने चाहिए, क्योंकि लोड लाइब्रेरी के साथ लोड करते समय उन्हें सही रूप से प्रारंभ नहीं किया जाता है।

पीथ्रेड्स कार्यान्वयन

Pthreads API में, थ्रेड के लिए स्थानीय मेमोरी को थ्रेड-विशिष्ट डेटा शब्द के साथ नामित किया गया है।

थ्रेड-विशिष्ट डेटा के लिए कुंजी बनाने और हटाने के लिए क्रमशः pthread_key_create and pthread_key_delete फ़ंक्शन का उपयोग किया जाता है। कुंजी का प्रकार स्पष्ट रूप से अपारदर्शी छोड़ दिया गया है और इसे pthread_key_tकहा जाता है। इस कुंजी को सभी थ्रेड्स द्वारा देखा जा सकता है। प्रत्येक थ्रेड में, कुंजी को pthread_setspecific के माध्यम से थ्रेड-विशिष्ट डेटा से जोड़ा जा सकता है। डेटा को बाद में pthread_getspecific. का उपयोग करके पुनर्प्राप्त किया जा सकता है।

इसके अतिरिक्त pthread_key_create वैकल्पिक रूप से एक डिस्ट्रक्टर फ़ंक्शन को स्वीकार कर सकता है जिसे थ्रेड-विशिष्ट डेटा NULL नहीं होने पर थ्रेड निकास पर स्वचालित रूप से कॉल किया जाएगा। विध्वंसक कुंजी से जुड़े मान को पैरामीटर के रूप में प्राप्त करता है जिससे वह सफाई क्रियाएं (संवर्त कनेक्शन, मुफ्त मेमोरी इत्यादि) कर सकता है । यहां तक कि जब एक डिस्ट्रक्टर निर्दिष्ट किया जाता है, तब भी प्रोग्राम को प्रक्रिया स्तर पर थ्रेड-विशिष्ट डेटा को मुक्त करने के लिएpthread_key_delete को कॉल करना होगा (डिस्ट्रक्टर केवल थ्रेड के लिए स्थानीय डेटा को मुक्त करता है)।

भाषा-विशिष्ट कार्यान्वयन

उपयुक्त एपीआई कार्यों को कॉल करने के लिए प्रोग्रामर पर विश्वाश करने के अतिरिक्त , थ्रेड लोकल स्टोरेज (टीएलएस) का समर्थन करने के लिए प्रोग्रामिंग लैंग्वेज का विस्तार करना भी संभव है।

C और C++

C11 में, कीवर्ड __Thread_local का उपयोग थ्रेड-लोकल वेरिएबल्स को परिभाषित करने के लिए किया जाता है। हेडर <threads.h>, यदि समर्थित है, तोthread_localको उस कीवर्ड के पर्यायवाची के रूप में परिभाषित करता है। उदाहरण उपयोग:

#include <threads.h>
thread_local int foo = 0;

C++11 thread_local[2] कीवर्ड प्रस्तुत करता है जिसका उपयोग निम्नलिखित स्थितियों में किया जा सकता है

  • नामस्थान स्तर (वैश्विक) वेरिएबल
  • फ़ाइल स्थिर वेरिएबल
  • कार्य स्थिर वेरिएबल
  • स्थिर सदस्य वेरिएबल

इसके अतिरिक्त, विभिन्न संकलक कार्यान्वयन थ्रेड-स्थानीय वेरिएबल घोषित करने के विशिष्ट विधि प्रदान करते हैं:


विस्टा और सर्वर 2008 से पहले के विंडोज़ संस्करणों पर, __declspec(thread) DLL में तभी काम करता है जब वे DLL निष्पादन योग्य से बंधे होते हैं, और LoadLibrary() से लोड किए गए लोगों के लिए काम नहीं करेंगे (सुरक्षा दोष या डेटा करप्शन हो सकता है)।[7]

सामान्य लिस्प (और शायद अन्य बोलियाँ)

कॉमन लिस्प स्कोप (कंप्यूटर साइंस) या डायनेमिक स्कोपिंग वेरिएबल्स नामक सुविधा प्रदान करता है।

डायनेमिक वेरिएबल में एक बंधन होता है जो किसी फ़ंक्शन के आह्वान और उस फ़ंक्शन द्वारा बुलाए गए सभी चिल्ड्रन के लिए निजी होता है।

यह अमूर्तता स्वाभाविक रूप से थ्रेड-विशिष्ट स्टोरेज के लिए मैप करती है, और थ्रेड्स प्रदान करने वाले लिस्प कार्यान्वयन ऐसा करते हैं। सामान्य लिस्प में कई मानक गतिशील वेरिएबल होते हैं, और इसलिए धागे को लैंग्वेज के कार्यान्वयन में समझदारी से नहीं जोड़ा जा सकता है, इन वेरिएबल के बिना गतिशील बंधन में थ्रेड-स्थानीय शब्दार्थ हैं।

उदाहरण के लिए मानक वेरिएबल *print-base* डिफ़ॉल्ट रेडिक्स निर्धारित करता है जिसमें पूर्णांक मुद्रित होते हैं। यदि यह वेरिएबल ओवरराइड किया गया है, तो सभी संलग्न कोड एक वैकल्पिक रेडिक्स में पूर्णांक प्रिंट करेंगे:

;;; function foo and its children will print
;; in hexadecimal:
(let ((*print-base* 16)) (foo))

यदि फ़ंक्शंस अलग-अलग थ्रेड्स पर समवर्ती रूप से निष्पादित हो सकते हैं, तो यह बाइंडिंग उचित रूप से थ्रेड-लोकल होनी चाहिए, अन्यथा प्रत्येक थ्रेड इस बात से लड़ेगा कि ग्लोबल प्रिंटिंग रेडिक्स को कौन नियंत्रित करता है।

D

D (प्रोग्रामिंग भाषा) संस्करण 2 में, सभी स्थिर और ग्लोबल वेरिएबल डिफ़ॉल्ट रूप से थ्रेड-लोकल हैं और अन्य लैंग्वेज में सामान्य ग्लोबल और स्थिर वेरिएबल के समान सिंटैक्स के साथ घोषित किए जाते हैं। साझा किए गए कीवर्ड का उपयोग करके ग्लोबल वेरिएबल का स्पष्ट रूप से अनुरोध किया जाना चाहिए:

int threadLocal;  // This is a thread-local variable.
shared int global;  // This is a global variable shared with all threads.

साझा किया गया कीवर्ड स्टोरेज क्लास और क्वालीफायर टाइप करें दोनों के रूप में काम करता है - साझा वेरिएबल कुछ प्रतिबंधों के अधीन हैं जो डेटा अखंडता को स्थिर रूप से प्रयुक्त करते हैं।[9] इन प्रतिबंधों के बिना क्लासिक ग्लोबल वेरिएबल घोषित करने के लिए, असुरक्षित __gshared कीवर्ड का उपयोग किया जाना चाहिए:[10]

__gshared int global;  // This is a plain old global variable.


जावा

जावा में, थ्रेड-लोकल वेरिएबल्स को थ्रेडलोकल क्लास ऑब्जेक्ट द्वारा कार्यान्वित किया जाता है। ThreadLocalमें T प्रकार का वेरिएबल है, जिसे गेट/सेट विधियों के माध्यम से एक्सेस किया जा सकता है। उदाहरण के लिए, थ्रेडलोकल वैरिएबल होल्डिंग इंटीजर मान इस तरह दिखता है:

private static final ThreadLocal<Integer> myThreadLocalInteger = new ThreadLocal<Integer>();

कम से कम ओरेकल/ओपनजेडीके के लिए, जावा थ्रेडिंग के अन्य पहलुओं के लिए ओएस थ्रेड का उपयोग किए जाने के अतिरिक्त यह देशी थ्रेड-लोकल स्टोरेज का उपयोग नहीं करता है। इसके अतिरिक्त , प्रत्येक थ्रेड ऑब्जेक्ट थ्रेडलोकल ऑब्जेक्ट्स के एक (गैर-थ्रेड-सुरक्षित) मानचित्र को उनके मानों में संग्रहीत करता है (जैसा कि प्रत्येक थ्रेडलोकल के विपरीत थ्रेड ऑब्जेक्ट्स का मानचित्र मानों के लिए होता है और प्रदर्शन ओवरहेड होता है)।[11]


.NET लैंग्वेज : C# और अन्य

C# जैसी .NET फ्रेमवर्क भाषाओं में, स्थिर फ़ील्ड को थ्रेडस्टैटिक विशेषता के साथ चिह्नित किया जा सकता है

class FooBar
{
    [ThreadStatic]
    private static int _foo;
}

.NET Framework 4.0 में System.Threading.ThreadLocal<T> वर्ग थ्रेड आवंटित करने और आलसी लोड करने के लिए उपलब्ध है -स्थानीय चर।

.NET फ्रेमवर्क 4.0 में System.Threading.ThreadLocal<T> क्लास थ्रेड-लोकल वेरिएबल्स को आवंटित करने और आसानी से लोड करने के लिए उपलब्ध है।

class FooBar
{
    private static System.Threading.ThreadLocal<int> _foo;
}

इसके अतिरिक्त a API गतिशील रूप से थ्रेड-स्थानीय वेरिएबल आवंटित करने के लिए उपलब्ध है।

वस्तु पास्कल

ऑब्जेक्ट पास्कल (डेल्फी (प्रोग्रामिंग भाषा) ) या फ़्री पास्कल में थ्रेड-लोकल स्टोरेज का उपयोग करके वेरिएबल घोषित करने के लिए 'var' के अतिरिक्त थ्रेडवार आरक्षित कीवर्ड का उपयोग किया जा सकता है।

var
   mydata_process: integer;
threadvar
   mydata_threadlocal: integer;


उद्देश्य-c

कोको, जीएनयूस्टेप और ओपनस्टेप में, प्रत्येक NSThreadऑब्जेक्ट में एक थ्रेड-लोकल डिक्शनरी होती है जिसे थ्रेड की threadDictionary विधि के माध्यम से एक्सेस किया जा सकता है।

NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary];
dict[@"A key"] = @"Some data";


पर्ल

व्यापक पर्ल आर्काइव नेटवर्क (सीपीएएन) पर उपस्थित कोड का एक बड़ा भाग पहले से ही उपस्थित होने के बाद लैंग्वेज के विकास में पर्ल थ्रेड्स को देर से जोड़ा गया था। इस प्रकार, डिफ़ॉल्ट रूप से पर्ल में थ्रेड्स उपस्थित गैर-थ्रेड-जागरूक कोड पर थ्रेड्स के प्रभाव को कम करने के लिए, सभी वेरिएबल्स के लिए अपना स्थानीय स्टोरेज लेते हैं। पर्ल में, एक विशेषता का उपयोग करके एक थ्रेड-साझा वेरिएबल बनाया जा सकता है:

use threads;
use threads::shared;

my $localvar;
my $sharedvar :shared;


प्योरबेसिक

PureBasic में थ्रेड वेरिएबल्स कीवर्ड थ्रेडेड के साथ घोषित किए जाते हैं।

Threaded Var


पायथन

पायथन (प्रोग्रामिंग भाषा) संस्करण 2.4 या बाद में, थ्रेडिंग मॉड्यूल में स्थानीय वर्ग का उपयोग थ्रेड-लोकल स्टोरेज बनाने के लिए किया जा सकता है।

import threading
mydata = threading.local()
mydata.x = 1


रूबी

रूबी (प्रोग्रामिंग भाषा) []=/[] विधियों का उपयोग करके थ्रेड-स्थानीय वेरिएबल बना/एक्सेस कर सकती है:

Thread.current[:user_id] = 1


रस्ट

थ्रेड_लोकल का उपयोग करके रस्ट में thread_local! वैरिएबल बनाए जा सकते हैं! रस्ट मानक पुस्तकालय द्वारा प्रदान किया गया मैक्रो:

use std::cell::RefCell;
use std::thread;

thread_local!(static FOO: RefCell<u32> = RefCell::new(1));

FOO.with(|f| {
    assert_eq!(*f.borrow(), 1);
    *f.borrow_mut() = 2;
});

// each thread starts out with the initial value of 1, even though this thread already changed its copy of the thread local value to 2
let t = thread::spawn(move || {
    FOO.with(|f| {
        assert_eq!(*f.borrow(), 1);
        *f.borrow_mut() = 3;
    });
});

// wait for the thread to complete and bail out on panic
t.join().unwrap();

// original thread retains the original value of 2 despite the child thread changing the value to 3 for that thread
FOO.with(|f| {
    assert_eq!(*f.borrow(), 2);
});


यह भी देखें

  • ओपनएमपी समानांतर प्रोसेसर कुछ हार्डवेयर के लिए समर्थन करता है
  • साझा मेमोरी मेमोरी पृष्ठों तक पहुंच और कॉन्फ़िगरेशन (सीपीयू और या कर्नेल समर्थित, यदि समर्थित हो)
  • संदर्भ स्विच को टास्क स्विचिंग भी कहा जाता है, थ्रेड्स, पेज हार्डवेयर त्वरित और या कर्नेल प्रदान किए जाते हैं
  • सेमाफोर (प्रोग्रामिंग) लॉक, यदि (सीपीयू) मल्टी-पोर्टेड मेमोरी को पर्याप्त रूप से सपोर्ट नहीं करता है (सीपीयू फ्रीज को रोकें)

संदर्भ

  1. Pietrek, Matt (May 2006). "हुड के नीचे". MSDN. Retrieved 6 April 2010.
  2. Section 3.7.2 in C++11 standard
  3. IBM XL C/C++: Thread-local storage
  4. GCC 3.3.1: Thread-Local Storage
  5. Clang 2.0: release notes
  6. Intel C++ Compiler 8.1 (linux) release notes: Thread-local Storage
  7. 7.0 7.1 Visual Studio 2003: "Thread Local Storage (TLS)". Microsoft Docs.
  8. Intel C++ Compiler 10.0 (windows): Thread-local storage
  9. Alexandrescu, Andrei (6 July 2010). Chapter 13 - Concurrency. p. 3. Retrieved 3 January 2014. {{cite book}}: |website= ignored (help)
  10. Bright, Walter (12 May 2009). "साझा करने के लिए माइग्रेट करना". dlang.org. Retrieved 3 January 2014.
  11. "How is Java's ThreadLocal implemented under the hood?". Stack Overflow. Stack Exchange. Retrieved 27 December 2015.


बाहरी संबंध