C # তে কি কেউ অস্থির কীওয়ার্ডের একটি ভাল ব্যাখ্যা সরবরাহ করতে পারে? এটি কোন সমস্যার সমাধান করে এবং কোনটি সমাধান করে না? কোন ক্ষেত্রে এটি আমাকে লকিংয়ের ব্যবহারটি সংরক্ষণ করবে?
C # তে কি কেউ অস্থির কীওয়ার্ডের একটি ভাল ব্যাখ্যা সরবরাহ করতে পারে? এটি কোন সমস্যার সমাধান করে এবং কোনটি সমাধান করে না? কোন ক্ষেত্রে এটি আমাকে লকিংয়ের ব্যবহারটি সংরক্ষণ করবে?
উত্তর:
আমি মনে করি না এরিক লিপার্ট ( মূলটিতে জোর দেওয়া) এর চেয়ে উত্তর দেওয়ার জন্য এর চেয়ে ভাল আর কোনও ব্যক্তি আছে :
সি # তে, "অস্থির" এর অর্থ কেবল "" এই পরিবর্তনশীলটিতে সংকলক এবং জিটার কোনও কোড পুনরায় অর্ডারিং না করে বা ক্যাচিং অপ্টিমাইজেশানগুলি নিবন্ধন করে না তা নিশ্চিত করুন "। এর অর্থ "প্রসেসরদের যা করা দরকার তা করতে বলুন যাতে আমি সর্বশেষতম মানটি পড়ছি তা নিশ্চিত করার জন্য, যদিও এর অর্থ অন্য প্রসেসরগুলি থামিয়ে দেওয়া এবং তাদের ক্যাশের সাথে মূল স্মৃতি সিঙ্ক্রোনাইজ করা" means
আসলে, যে শেষ বিট একটি মিথ্যা। অস্থির পড়া এবং লেখার সত্যিকারের শব্দার্থবিজ্ঞানগুলি এখানে আমি উল্লেখ করেছি তার চেয়ে অনেক জটিল; প্রকৃতপক্ষে তারা গ্যারান্টি দেয় না যে প্রতিটি প্রসেসর এটি কী করে বন্ধ করে দেয় এবং মূল মেমোরিতে / থেকে ক্যাশে আপডেট করে। বরং তারা পড়ার আগে এবং লেখার পরে স্মৃতিতে কীভাবে অ্যাক্সেস হয় সে সম্পর্কে দুর্বল গ্যারান্টি দেয় তারা একে অপরের প্রতি শ্রদ্ধার সাথে অর্ডার করার জন্য পর্যবেক্ষণ করতে পারে । একটি নতুন থ্রেড তৈরি করা, কোনও তালা প্রবেশ করা, বা ইন্টারলকড পরিবারের কোনও পদ্ধতির ব্যবহারের মতো কিছু ক্রিয়াকলাপ ক্রমবিন্যাসের পর্যবেক্ষণ সম্পর্কে দৃ stronger় গ্যারান্টি প্রবর্তন করে। আপনি আরও বিশদ জানতে চাইলে সি # 4.0 স্পেসিফিকেশনের বিভাগ 3.10 এবং 10.5.3 পড়ুন।
সত্যই, আমি আপনাকে কখনও অস্থির ক্ষেত্র তৈরি থেকে নিরুৎসাহিত করি । অস্থির ক্ষেত্রগুলি এমন একটি লক্ষণ যা আপনি নিখুঁত পাগল হয়ে যাচ্ছেন: আপনি লকটি স্থাপন না করে দুটি ভিন্ন থ্রেডে একই মানটি পড়তে এবং লেখার চেষ্টা করছেন। লকগুলি গ্যারান্টি দেয় যে লকের ভিতরে থাকা মেমরিটি পড়া বা সংশোধন করা হয়েছে তা সামঞ্জস্যপূর্ণভাবে পর্যবেক্ষণ করা হয়, লকগুলি গ্যারান্টি দেয় যে কেবলমাত্র একটি থ্রেড একটি সময়ে প্রদত্ত মেমরির একটি অংশকে অ্যাক্সেস করে। লকটি খুব ধীরগতির অবস্থার সংখ্যা খুব কম, এবং আপনি কোডটি ভুল পেতে পারেন এমন সম্ভাবনা কারণ আপনি সঠিক মেমরির মডেলটি বুঝতে পারছেন না খুব বড়। ইন্টারলকড অপারেশনের সবচেয়ে তুচ্ছ ব্যবহার ব্যতীত আমি কোনও ল-লক কোড লেখার চেষ্টা করি না। আমি "অস্থির" ব্যবহার প্রকৃত বিশেষজ্ঞদের কাছে রেখে দিই।
আরও পড়ার জন্য দেখুন:
volatile
ঘটবে
যদি আপনি উদ্বায়ী কীওয়ার্ডটি কী সম্পর্কে কিছুটা আরও প্রযুক্তিগত পেতে চান তবে নীচের প্রোগ্রামটি বিবেচনা করুন (আমি ডেভস্টুডিও 2005 ব্যবহার করছি):
#include <iostream>
void main()
{
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
j += i;
}
for (volatile int i = 0 ; i < 100 ; ++i)
{
j += i;
}
std::cout << j;
}
স্ট্যান্ডার্ড অপ্টিমাইজড (রিলিজ) সংকলক সেটিংস ব্যবহার করে, সংকলকটি নিম্নলিখিত এসেমব্লার (আইএ 32) তৈরি করে:
void main()
{
00401000 push ecx
int j = 0;
00401001 xor ecx,ecx
for (int i = 0 ; i < 100 ; ++i)
00401003 xor eax,eax
00401005 mov edx,1
0040100A lea ebx,[ebx]
{
j += i;
00401010 add ecx,eax
00401012 add eax,edx
00401014 cmp eax,64h
00401017 jl main+10h (401010h)
}
for (volatile int i = 0 ; i < 100 ; ++i)
00401019 mov dword ptr [esp],0
00401020 mov eax,dword ptr [esp]
00401023 cmp eax,64h
00401026 jge main+3Eh (40103Eh)
00401028 jmp main+30h (401030h)
0040102A lea ebx,[ebx]
{
j += i;
00401030 add ecx,dword ptr [esp]
00401033 add dword ptr [esp],edx
00401036 mov eax,dword ptr [esp]
00401039 cmp eax,64h
0040103C jl main+30h (401030h)
}
std::cout << j;
0040103E push ecx
0040103F mov ecx,dword ptr [__imp_std::cout (40203Ch)]
00401045 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)]
}
0040104B xor eax,eax
0040104D pop ecx
0040104E ret
আউটপুটটির দিকে তাকিয়ে, সংকলকটি জে ভেরিয়েবলের মান সঞ্চয় করতে ইকেক্স রেজিস্টার ব্যবহার করার সিদ্ধান্ত নিয়েছে। অ-উদ্বায়ী লুপের জন্য (প্রথম) সংকলকটি iax নিবন্ধকে নিযুক্ত করেছে। মোটামুটি সহজবোধ্য. বেশ কয়েকটি আকর্ষণীয় বিট রয়েছে যদিও - লি ইবিএক্স, [ইবিএক্স] নির্দেশনাটি কার্যকরভাবে একটি মাল্টিবাইট নপ নির্দেশনা যাতে লুপটি 16 বাইট সারিবদ্ধ মেমরি ঠিকানায় যায় address অন্যটি কোনও ইন ইক্স নির্দেশ ব্যবহার না করে লুপের কাউন্টারকে বাড়ানোর জন্য এডএক্স ব্যবহার। অ্যাঙ্ক রেগ, রেগ নির্দেশাবলীর ইনক রেগ নির্দেশের তুলনায় কয়েকটি আইএ 32 সিলে কম ল্যাটেন্সি রয়েছে তবে কখনও উচ্চতর লেটেন্সি নেই।
অস্থির লুপ কাউন্টার সহ লুপের জন্য এখন। কাউন্টারটি [esp] এ সংরক্ষণ করা হয় এবং উদ্বায়ী কীওয়ার্ডটি সংকলককে বলে যে মানটি সর্বদা মেমরি থেকে লেখা / লিখিত হওয়া উচিত এবং কখনও কোনও নিবন্ধকের কাছে বরাদ্দ করা উচিত নয়। সংকলক এমনকি কাউন্টারের মান আপডেট করার সময় লোড / ইনক্রিমেন্ট / স্টোরটি তিনটি স্বতন্ত্র পদক্ষেপ হিসাবে (লোড ইক্স, ইন ইক্স, সেভ ইক্স) না করে চলে যায়, পরিবর্তে মেমরিটি একক নির্দেশায় সরাসরি পরিবর্তিত হয় (একটি অ্যাড মেম , রেগ)। কোডটি যেভাবে তৈরি করা হয়েছে তা নিশ্চিত করে যে লুপ কাউন্টারটির মান সর্বদা একক সিপিইউ কোর প্রসঙ্গে আপ-টু-ডেট। ডেটাতে কোনও অপারেশনের ফলে দুর্নীতি বা ডেটা হারাতে পারে না (সুতরাং লোড / ইনক / স্টোরটি ব্যবহার না করা যেহেতু স্টোরের মধ্যে ক্ষতি হ্রাসের সময় মূল্য পরিবর্তন হতে পারে)। যেহেতু বর্তমান নির্দেশ সম্পূর্ণ হয়ে গেলে কেবল বাধা কেবল পরিবেশন করা যায়,
একবার আপনি সিস্টেমে একটি দ্বিতীয় সিপিইউ পরিচয় করিয়ে দিলে, অস্থায়ী কীওয়ার্ড একই সাথে অন্য সিপিইউ দ্বারা আপডেট হওয়া ডেটা থেকে রক্ষা করবে না। উপরের উদাহরণে, কোনও সম্ভাব্য দুর্নীতি পেতে আপনার ডেটা আন-সাইনাইড করা দরকার। অস্থিতিশীল কীওয়ার্ডটি সম্ভাব্য দুর্নীতি রোধ করতে পারে না যদি ডেটাটিকে পরমাণুভাবে পরিচালনা করা যায় না, উদাহরণস্বরূপ, যদি লুপের কাউন্টারটি দীর্ঘ দীর্ঘ (64৪ বিট) টাইপের হয় তবে তার মানটি আপডেট করার জন্য দুটি 32 বিট অপারেশন প্রয়োজন যা একটি বাধা ঘটতে পারে এবং ডেটা পরিবর্তন করতে পারে।
সুতরাং, উদ্বায়ী কীওয়ার্ডটি কেবলমাত্র প্রান্তিককরণের জন্য ভাল যা দেশীয় নিবন্ধগুলির আকারের চেয়ে কম বা সমান হয় যেগুলি অপারেশন সর্বদা পারমাণবিক থাকে।
অস্থিতিশীল কীওয়ার্ডটি আইও অপারেশনগুলির সাথে ব্যবহার করার জন্য ধারণা করা হয়েছিল যেখানে আইও নিয়মিত পরিবর্তিত হবে তবে একটি ধ্রুব ঠিকানা ছিল যেমন একটি মেমরি ম্যাপযুক্ত ইউআআরটি ডিভাইস, এবং সংকলকটি ঠিকানা থেকে পঠিত প্রথম মানটির পুনরায় ব্যবহার করা উচিত নয়।
যদি আপনি বড় ডেটা পরিচালনা করছেন বা একাধিক সিপিইউ রয়েছে তবে ডেটা অ্যাক্সেসটি সঠিকভাবে পরিচালনা করতে আপনার উচ্চ স্তরের (ওএস) লকিং সিস্টেমের প্রয়োজন হবে।
যদি আপনি .NET 1.1 ব্যবহার করে থাকেন তবে ডাবল চেকড লকিংয়ের সময় ভোল্টাইল কিওয়ার্ডটি প্রয়োজন। কেন? .NET 2.0 এর আগে, নিম্নলিখিত দৃশ্যের ফলে একটি দ্বিতীয় থ্রেড অ-নালকে অ্যাক্সেস করতে পারে, তবুও সম্পূর্ণরূপে নির্মিত নয়:
.NET 2.0 এর পূর্বে কনস্ট্রাক্টর চলমান শেষ হওয়ার আগে এই.ফুকে ফু-র নতুন দৃষ্টান্ত দেওয়া যেতে পারে। এই ক্ষেত্রে, দ্বিতীয় থ্রেড আসতে পারে (থ্রেড 1 এর ফোর কনস্ট্রাক্টরের কল করার সময়) এবং নিম্নলিখিতটি অনুভব করতে পারে:
.NET 2.0 এর পূর্বে, আপনি এইটিকে ঘোষণা করতে পারতেন এই সমস্যাটি ঘাটানোর জন্য এটি অস্থায়ী হিসাবে oo .NET 2.0 থেকে, ডাবল চেকড লকিংয়ের জন্য আপনার আর অস্থায়ী কীওয়ার্ড ব্যবহার করার দরকার নেই।
উইকিপিডিয়া আসলে ডাবল চেকড লকিং সম্পর্কিত একটি ভাল নিবন্ধ আছে এবং সংক্ষিপ্তভাবে এই বিষয়টিতে স্পর্শ করেছে: http://en.wikedia.org/wiki/Double-checked_locking
foo
? থ্রেড 1 লকিং নয় this.bar
এবং তাই কেবল থ্রেড 1 সময়মতো একটি পয়েন্ট পয়েন্টে ফু শুরু করতে সক্ষম হবে? আমি বলতে চাইছি, লকটি আবার প্রকাশের পরে আপনি মানটি পরীক্ষা করে দেখুন, যাইহোক যাইহোক এটি থ্রেড 1 থেকে নতুন মান হওয়া উচিত
কখনও কখনও, সংকলকটি একটি ক্ষেত্রকে অনুকূলিত করবে এবং এটি সংরক্ষণ করার জন্য একটি রেজিস্টার ব্যবহার করবে। যদি থ্রেড 1 ফিল্ডে একটি লিখন করে এবং অন্য থ্রেড এটি অ্যাক্সেস করে, যেহেতু আপডেটটি কোনও রেজিস্টারে সংরক্ষণ করা হয়েছিল (এবং মেমরি নয়), দ্বিতীয় থ্রেডটি বাসি ডেটা পেতে পারে।
আপনি উদ্বায়ী কীওয়ার্ডটি সংকলককে বলেছিলেন যে "আমি চাই আপনি এই মানটি স্মৃতিতে সঞ্চয় করুন"। এটি গ্যারান্টি দেয় যে ২ য় থ্রেড সর্বশেষ মানটি পুনরুদ্ধার করে।
এমএসডিএন থেকে : অস্থায়ী সংশোধকটি সাধারণত এমন ক্ষেত্রের জন্য ব্যবহৃত হয় যা অ্যাক্সেসকে সিরিয়ালাইজ করতে লক স্টেটমেন্টটি ব্যবহার না করে একাধিক থ্রেড দ্বারা অ্যাক্সেস করা হয়। অস্থির পরিবর্তনকারী ব্যবহার নিশ্চিত করে যে একটি থ্রেড অন্য থ্রেড দ্বারা লিখিত সর্বাধিক আপ-টু-ডেট মানটি পুনরুদ্ধার করে।
সিএলআর নির্দেশাবলী অনুকূলিত করতে পছন্দ করে, সুতরাং আপনি কোডের কোনও ক্ষেত্র অ্যাক্সেস করার সময় এটি সর্বদা ক্ষেত্রের বর্তমান মান অ্যাক্সেস করতে পারে না (এটি স্ট্যাক থেকে হতে পারে ইত্যাদি) etc ক্ষেত্রের চিহ্ন হিসাবে ক্ষেত্রের volatile
বর্তমান মানটি নির্দেশের মাধ্যমে অ্যাক্সেস করেছে তা নিশ্চিত করে। এটি কার্যকর হয় যখন মানটি আপনার প্রোগ্রামের সামঞ্জস্যভাবে থ্রেড বা অপারেটিং সিস্টেমের মধ্যে চলমান অন্য কোনও কোডের মাধ্যমে (একটি লকিং-না অবস্থায়) সংশোধন করা যায়।
আপনি অবশ্যই কিছু অপ্টিমাইজেশন হারাতে পারেন তবে এটি কোডটিকে আরও সরল রাখে।
আমি জয়দীপ কঞ্জিলালের এই নিবন্ধটি খুব সহায়ক বলে মনে করেছি!
When you mark an object or a variable as volatile, it becomes a candidate for volatile reads and writes. It should be noted that in C# all memory writes are volatile irrespective of whether you are writing data to a volatile or a non-volatile object. However, the ambiguity happens when you are reading data. When you are reading data that is non-volatile, the executing thread may or may not always get the latest value. If the object is volatile, the thread always gets the most up-to-date value
আমি এটি এখানে রেফারেন্সের জন্য রেখে দেব
সংকলকটি কখনও কখনও এটির অনুকূলিতকরণের জন্য কোডের বিবৃতিগুলির ক্রম পরিবর্তন করে। সাধারণত এটি একক থ্রেডযুক্ত পরিবেশে সমস্যা নয়, তবে এটি বহু-থ্রেডযুক্ত পরিবেশে সমস্যা হতে পারে। নিম্নলিখিত উদাহরণ দেখুন:
private static int _flag = 0;
private static int _value = 0;
var t1 = Task.Run(() =>
{
_value = 10; /* compiler could switch these lines */
_flag = 5;
});
var t2 = Task.Run(() =>
{
if (_flag == 5)
{
Console.WriteLine("Value: {0}", _value);
}
});
আপনি টি 1 এবং টি 2 চালিয়ে গেলে আপনি ফলাফল হিসাবে কোনও আউটপুট বা "মান: 10" আশা করবেন না। এটি হতে পারে যে সংকলক টি 1 ফাংশনের অভ্যন্তরে লাইনটি স্যুইচ করে। T2 যদি কার্যকর হয় তবে এটি হতে পারে _ফ্ল্যাগের মান 5 হয় তবে _ভ্যালুতে 0 থাকে। সুতরাং প্রত্যাশিত যুক্তিটি ভাঙ্গা যেতে পারে।
এটি ঠিক করতে আপনি অস্থায়ী কীওয়ার্ড ব্যবহার করতে পারেন যা আপনি ক্ষেত্রে প্রয়োগ করতে পারেন। এই বিবৃতিটি কম্পাইলার অপ্টিমাইজেশানগুলি অক্ষম করে যাতে আপনি কোডে সঠিক ক্রমটি চাপিয়ে নিতে পারেন।
private static volatile int _flag = 0;
আপনার যদি সত্যই এটির প্রয়োজন হয় তবেই আপনার অস্থির ব্যবহার করা উচিত , কারণ এটি নির্দিষ্ট সংকলক অপ্টিমাইজেশান অক্ষম করে, এতে কার্যকারিতা ক্ষতিগ্রস্থ হবে। এটি সমস্ত। নেট ভাষা দ্বারা সমর্থিত নয় (ভিজ্যুয়াল বেসিক এটি সমর্থন করে না), তাই এটি ভাষার আন্তঃব্যবযোগিতা বাধা দেয়।
সুতরাং এই সমস্ত সংক্ষেপে, প্রশ্নের সঠিক উত্তর হ'ল: যদি আপনার কোড ২.০ রানটাইম বা তার পরে চালানো হয় তবে অস্থায়ী কীওয়ার্ডটি প্রায় প্রয়োজন হয় না এবং অযথা ব্যবহার করা হলে ভালের চেয়ে বেশি ক্ষতি করে। আইই কখনও এটি ব্যবহার করবেন না। তবে রানটাইমের আগের সংস্করণগুলিতে স্ট্যাটিক ক্ষেত্রগুলিতে যথাযথ ডাবল চেক লকিংয়ের জন্য এটি প্রয়োজন। বিশেষত স্থিতিশীল ক্ষেত্র যাদের ক্লাসে স্থির শ্রেণীর সূচনা কোড রয়েছে।
একাধিক থ্রেড একটি চলক অ্যাক্সেস করতে পারেন। সর্বশেষ আপডেটটি চলকটিতে থাকবে on