थ्रेड-लोकल स्टोरेज
This article needs additional citations for verification. (December 2012) (Learn how and when to remove this template message) |
कंप्यूटर प्रोग्रामिंग में, थ्रेड-लोकल स्टोरेज (TLS) एक स्मृति प्रबंधन मेथड है जो स्थैतिक स्मृति आवंटन या ग्लोबल कंप्यूटर भंडारण को थ्रेड (कंप्यूटिंग) के लिए लोकल का उपयोग करता है।
जबकि आधुनिक प्रोग्रामिंग में वैश्विक चरों के उपयोग को आम तौर पर हतोत्साहित किया जाता है, UNIX जैसे लीगेसी ऑपरेटिंग सिस्टम को यूनिप्रोसेसर हार्डवेयर के लिए डिज़ाइन किया गया है और प्री-रीएंट्रेंसी (कंप्यूटिंग) एपीआई के शब्दार्थ को बनाए रखने के लिए कुछ अतिरिक्त तंत्र की आवश्यकता होती है। ऐसी स्थितियों का एक उदाहरण है जहां फ़ंक्शन त्रुटि स्थिति सेट करने के लिए वैश्विक चर का उपयोग करते हैं (उदाहरण के लिए वैश्विक चर errno
सी पुस्तकालय के कई कार्यों द्वारा उपयोग किया जाता है)। अगर errno
एक वैश्विक चर थे, एक थ्रेड पर एक सिस्टम फ़ंक्शन की कॉल किसी भिन्न थ्रेड पर सिस्टम फ़ंक्शन के कॉल द्वारा पहले सेट किए गए मान को अधिलेखित कर सकती है, संभवत: उस भिन्न थ्रेड पर कोड का पालन करने से पहले त्रुटि स्थिति की जांच कर सकती है। समाधान होना है errno
ऐसा चर हो जो ऐसा लगता है कि यह वैश्विक है, लेकिन वास्तव में प्रति थ्रेड एक बार मौजूद है- यानी, यह थ्रेड-लोकल स्टोरेज में रहता है। एक दूसरा उपयोग मामला एक वैश्विक चर में जानकारी जमा करने वाले कई सूत्र होंगे। दौड़ की स्थिति से बचने के लिए, इस वैश्विक चर की प्रत्येक पहुंच को एक लॉक (कंप्यूटर विज्ञान) द्वारा संरक्षित करना होगा। वैकल्पिक रूप से, प्रत्येक थ्रेड एक थ्रेड-लोकल वेरिएबल में जमा हो सकता है (जो कि, परिभाषा के अनुसार, अन्य थ्रेड्स से पढ़ा या लिखा नहीं जा सकता है, जिसका अर्थ है कि दौड़ की स्थिति नहीं हो सकती है)। थ्रेड्स को केवल अपने स्वयं के थ्रेड-स्थानीय चर से एक एकल, सही मायने में वैश्विक चर में अंतिम संचय को सिंक्रनाइज़ करना होगा।
कई प्रणालियाँ थ्रेड-लोकल मेमोरी ब्लॉक के आकार पर प्रतिबंध लगाती हैं, वास्तव में अक्सर बल्कि तंग सीमाएँ। दूसरी ओर, यदि कोई सिस्टम कम से कम एक स्मृति पता (पॉइंटर) आकार का वेरिएबल थ्रेड-लोकल प्रदान कर सकता है, तो यह मनमाने ढंग से आकार के मेमोरी ब्लॉक को थ्रेड-लोकल तरीके से उपयोग करने की अनुमति देता है, इस तरह के मेमोरी ब्लॉक को गतिशील रूप से आवंटित करके और स्टोर करके थ्रेड-लोकल वैरिएबल में उस ब्लॉक का मेमोरी एड्रेस। कम निर्देश सेट कंप्यूटर मशीनों पर, कॉलिंग कन्वेंशन अक्सर इस उपयोग के लिए थ्रेड पॉइंटर रजिस्टर आरक्षित करता है।
विंडोज कार्यान्वयन
अप्लिकेशन प्रोग्रामिंग अंतरफलक (एपीआई) फ़ंक्शन TlsAlloc
अप्रयुक्त टीएलएस स्लॉट इंडेक्स प्राप्त करने के लिए इस्तेमाल किया जा सकता है; तब TLS स्लॉट इंडेक्स को 'प्रयुक्त' माना जाएगा। TlsGetValue
ई> और TlsSetValue
फ़ंक्शंस का उपयोग तब TLS स्लॉट इंडेक्स द्वारा पहचाने गए थ्रेड-लोकल वैरिएबल को मेमोरी एड्रेस पढ़ने और लिखने के लिए किया जाता है। TlsSetValue
केवल वर्तमान थ्रेड के लिए वेरिएबल को प्रभावित करता है। TlsFree
टीएलएस स्लॉट इंडेक्स जारी करने के लिए ई> फ़ंक्शन को कॉल किया जा सकता है।
प्रत्येक थ्रेड के लिए एक Win32 थ्रेड सूचना ब्लॉक है। इस ब्लॉक में प्रविष्टियों में से एक उस थ्रेड के लिए थ्रेड-लोकल स्टोरेज टेबल है।[1] TlsAlloc प्रत्येक कॉल के लिए इस तालिका में एक अनुक्रमणिका लौटाता है, अद्वितीय प्रति पता स्थान। प्रत्येक थ्रेड के पास थ्रेड-लोकल स्टोरेज टेबल की अपनी कॉपी होती है। इसलिए, प्रत्येक थ्रेड स्वतंत्र रूप से TlsSetValue(index) का उपयोग कर सकता है और TlsGetValue(index) के माध्यम से निर्दिष्ट मान प्राप्त कर सकता है, क्योंकि ये थ्रेड की अपनी तालिका में एक प्रविष्टि सेट और खोजते हैं।
TlsXxx फ़ंक्शन परिवार के अलावा, विंडोज़ एक्जीक्यूटेबल्स एक सेक्शन को परिभाषित कर सकते हैं जो निष्पादन प्रक्रिया के प्रत्येक थ्रेड के लिए एक अलग पृष्ठ पर मैप किया गया है। TlsXxx मानों के विपरीत, इन पृष्ठों में मनमाने और वैध पते हो सकते हैं। हालाँकि, ये पते प्रत्येक निष्पादन थ्रेड के लिए अलग-अलग हैं और इसलिए एसिंक्रोनस फ़ंक्शंस (जो एक अलग थ्रेड में निष्पादित हो सकते हैं) या अन्यथा कोड को पास नहीं किया जाना चाहिए, जो मानते हैं कि पूरी प्रक्रिया के भीतर एक वर्चुअल एड्रेस अद्वितीय है। TLS अनुभागों को पेजिंग का उपयोग करके प्रबंधित किया जाता है और इसका आकार पृष्ठ आकार (x86 मशीनों पर 4kB) तक निर्धारित किया जाता है। इस तरह के अनुभागों को केवल एक प्रोग्राम के मुख्य निष्पादन योग्य के अंदर परिभाषित किया जा सकता है - डायनामिक-लिंक लाइब्रेरी में ऐसे अनुभाग नहीं होने चाहिए, क्योंकि लोड लाइब्रेरी के साथ लोड करते समय उन्हें सही ढंग से प्रारंभ नहीं किया जाता है।
पीथ्रेड्स कार्यान्वयन
Pthreads API में, थ्रेड के लिए स्थानीय मेमोरी को थ्रेड-विशिष्ट डेटा शब्द के साथ नामित किया गया है।
कार्य pthread_key_create
और pthread_key_delete
थ्रेड-विशिष्ट डेटा के लिए कुंजी बनाने और हटाने के लिए क्रमशः उपयोग किया जाता है। कुंजी का प्रकार स्पष्ट रूप से अपारदर्शी छोड़ दिया जाता है और इसे कहा जाता है pthread_key_t
. यह कुंजी सभी धागों द्वारा देखी जा सकती है। प्रत्येक थ्रेड में, कुंजी को थ्रेड-विशिष्ट डेटा के माध्यम से जोड़ा जा सकता है pthread_setspecific
. डेटा को बाद में उपयोग करके पुनर्प्राप्त किया जा सकता है pthread_getspecific
.
इसके साथ ही pthread_key_create
यदि थ्रेड-विशिष्ट डेटा NULL नहीं है, तो वैकल्पिक रूप से एक विध्वंसक फ़ंक्शन को स्वीकार कर सकता है, जिसे थ्रेड निकास पर स्वचालित रूप से कॉल किया जाएगा। विध्वंसक कुंजी के साथ जुड़े मान को पैरामीटर के रूप में प्राप्त करता है ताकि यह क्लीनअप क्रियाएं (करीब कनेक्शन, मुक्त मेमोरी, आदि) कर सके। यहां तक कि जब एक विनाशक निर्दिष्ट किया जाता है, तब भी प्रोग्राम को कॉल करना चाहिए pthread_key_delete
थ्रेड-विशिष्ट डेटा को प्रक्रिया स्तर पर मुक्त करने के लिए (विध्वंसक केवल थ्रेड के लिए स्थानीय डेटा को मुक्त करता है)।
भाषा-विशिष्ट कार्यान्वयन
उपयुक्त एपीआई कार्यों को कॉल करने के लिए प्रोग्रामर पर भरोसा करने के अलावा, थ्रेड लोकल स्टोरेज (टीएलएस) का समर्थन करने के लिए प्रोग्रामिंग भाषा का विस्तार करना भी संभव है।
सी और सी ++
C11 (C मानक संशोधन) में, कीवर्ड _Thread_local
थ्रेड-लोकल वेरिएबल्स को परिभाषित करने के लिए उपयोग किया जाता है। शीर्षलेख <threads.h>
, यदि समर्थित है, परिभाषित करता है thread_local
उस कीवर्ड के पर्याय के रूप में। उदाहरण उपयोग:
#include <threads.h>
thread_local int foo = 0;
सी ++ 11 पेश करता है thread_local
[2] कीवर्ड जिसका उपयोग निम्नलिखित मामलों में किया जा सकता है
- नामस्थान स्तर (वैश्विक) चर
- फ़ाइल स्थिर चर
- कार्य स्थिर चर
- स्थिर सदस्य चर
इसके अलावा, विभिन्न संकलक कार्यान्वयन थ्रेड-स्थानीय चर घोषित करने के विशिष्ट तरीके प्रदान करते हैं:
- ओरेकल सोलारिस स्टूडियो सी/सी++, आईबीएम एक्सएल सी/सी++,[3] जीएनयू संकलक संग्रह,[4] बजना[5] और इंटेल सी ++ कंपाइलर (लिनक्स सिस्टम)[6] सिंटैक्स का उपयोग करें:
__thread int number;
- विजुअल सी ++ ,[7] इंटेल सी/सी++ (विंडोज़ सिस्टम),[8] सी ++ बिल्डर, और डिजिटल मंगल सी ++ सिंटैक्स का उपयोग करते हैं:
__declspec(thread) int number;
- C++बिल्डर सिंटैक्स का भी समर्थन करता है:
int __thread number;
Vista और Server 2008 से पहले के Windows संस्करणों पर, __declspec(thread)
DLL में तभी काम करता है जब वे DLL निष्पादन योग्य के लिए बाध्य होते हैं, और LoadLibrary() (एक सुरक्षा दोष या डेटा भ्रष्टाचार हो सकता है) के साथ लोड किए गए लोगों के लिए काम नहीं करेगा।[7]
सामान्य लिस्प (और शायद अन्य बोलियाँ)
कॉमन लिस्प स्कोप (कंप्यूटर साइंस) # डायनेमिक स्कोपिंग वेरिएबल्स नामक सुविधा प्रदान करता है।
डायनेमिक चर में एक बंधन होता है जो किसी फ़ंक्शन के आह्वान और उस फ़ंक्शन द्वारा बुलाए गए सभी बच्चों के लिए निजी होता है।
यह अमूर्तता स्वाभाविक रूप से थ्रेड-विशिष्ट स्टोरेज के लिए मैप करती है, और थ्रेड्स प्रदान करने वाले लिस्प कार्यान्वयन ऐसा करते हैं। सामान्य लिस्प में कई मानक गतिशील चर होते हैं, और इसलिए धागे को भाषा के कार्यान्वयन में समझदारी से नहीं जोड़ा जा सकता है, इन चरों के बिना गतिशील बंधन में थ्रेड-स्थानीय शब्दार्थ हैं।
उदाहरण के लिए मानक चर *print-base*
डिफ़ॉल्ट रेडिक्स निर्धारित करता है जिसमें पूर्णांक मुद्रित होते हैं। यदि यह चर ओवरराइड किया गया है, तो सभी संलग्न कोड एक वैकल्पिक रेडिक्स में पूर्णांक प्रिंट करेंगे:
;;; function foo and its children will print
;; in hexadecimal:
(let ((*print-base* 16)) (foo))
यदि फ़ंक्शंस अलग-अलग थ्रेड्स पर समवर्ती रूप से निष्पादित हो सकते हैं, तो यह बाइंडिंग उचित रूप से थ्रेड-लोकल होनी चाहिए, अन्यथा प्रत्येक थ्रेड इस बात से लड़ेगा कि ग्लोबल प्रिंटिंग रेडिक्स को कौन नियंत्रित करता है।
डी
डी (प्रोग्रामिंग भाषा) संस्करण 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
वर्ग (कंप्यूटर विज्ञान) वस्तु। थ्रेडलोकल टाइप टी का वेरिएबल रखता है, जिसे प्राप्त/सेट विधियों के माध्यम से एक्सेस किया जा सकता है। उदाहरण के लिए, थ्रेडलोकल वैरिएबल होल्डिंग इंटीजर वैल्यू इस तरह दिखता है:
private static final ThreadLocal<Integer> myThreadLocalInteger = new ThreadLocal<Integer>();
कम से कम ओरेकल/ओपनजेडीके के लिए, जावा थ्रेडिंग के अन्य पहलुओं के लिए ओएस थ्रेड का उपयोग किए जाने के बावजूद यह देशी थ्रेड-लोकल स्टोरेज का उपयोग नहीं करता है। इसके बजाए, प्रत्येक थ्रेड ऑब्जेक्ट थ्रेडलोकल ऑब्जेक्ट्स के एक (गैर-थ्रेड-सुरक्षित) मानचित्र को उनके मानों में संग्रहीत करता है (जैसा कि प्रत्येक थ्रेडलोकल के विपरीत थ्रेड ऑब्जेक्ट्स का मानचित्र मानों के लिए होता है और प्रदर्शन ओवरहेड होता है)।[11]
.NET भाषाएँ: C# और अन्य
सी शार्प (प्रोग्रामिंग भाषा)|सी# जैसी .NET फ्रेमवर्क भाषाओं में, स्थिर क्षेत्रों को थ्रेडस्टैटिक विशेषता के साथ चिह्नित किया जा सकता है:
class FooBar
{
[ThreadStatic]
private static int _foo;
}
.NET Framework 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;
उद्देश्य-सी
कोको (एपीआई), जीएनयूस्टेप और ओपनस्टेप में, प्रत्येक 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);
});
यह भी देखें
- OpenMP समानांतर प्रोसेसर कुछ हार्डवेयर के लिए समर्थन करता है
- साझा मेमोरी स्मृति पृष्ठों तक पहुंच और कॉन्फ़िगरेशन (सीपीयू और या कर्नेल समर्थित, यदि समर्थित हो)
- संदर्भ स्विच को टास्क स्विचिंग भी कहा जाता है, थ्रेड्स, पेज हार्डवेयर त्वरित और या कर्नेल प्रदान किए जाते हैं
- सेमाफोर (प्रोग्रामिंग) LOCK, अगर (सीपीयू) मल्टी-पोर्टेड मेमोरी को पर्याप्त रूप से सपोर्ट नहीं करता है (सीपीयू फ्रीज को रोकें)
संदर्भ
- ↑ Pietrek, Matt (May 2006). "हुड के नीचे". MSDN. Retrieved 6 April 2010.
- ↑ Section 3.7.2 in C++11 standard
- ↑ IBM XL C/C++: Thread-local storage
- ↑ GCC 3.3.1: Thread-Local Storage
- ↑ Clang 2.0: release notes
- ↑ Intel C++ Compiler 8.1 (linux) release notes: Thread-local Storage
- ↑ 7.0 7.1 Visual Studio 2003: "Thread Local Storage (TLS)". Microsoft Docs.
- ↑ Intel C++ Compiler 10.0 (windows): Thread-local storage
- ↑ Alexandrescu, Andrei (6 July 2010). Chapter 13 - Concurrency. p. 3. Retrieved 3 January 2014.
{{cite book}}
:|website=
ignored (help) - ↑ Bright, Walter (12 May 2009). "साझा करने के लिए माइग्रेट करना". dlang.org. Retrieved 3 January 2014.
- ↑ "How is Java's ThreadLocal implemented under the hood?". Stack Overflow. Stack Exchange. Retrieved 27 December 2015.
बाहरी संबंध
- ELF Handling For Thread-Local Storage — Document about an implementation in C or C++.
- ACE_TSS< TYPE > Class Template Reference
- RWTThreadLocal<Type> Class Template Documentation
- Article "Use thread-local Storage to Pass Thread Specific Data" by Doug Doedens
- "Thread-Local Storage" by Lawrence Crowl
- Article "It's Not Always Nice To Share" by Walter Bright
- Practical ThreadLocal usage in Java: http://www.captechconsulting.com/blogs/a-persistence-pattern-using-threadlocal-and-ejb-interceptors
- GCC "[1]"
- Rust "[2]"