সম্প্রতি, আমি "ম্যালোক থ্রেড নিরাপদ?" শিরোনাম সহ একটি প্রশ্ন জিজ্ঞাসা করেছি ? , এবং এর ভিতরে আমি জিজ্ঞাসা করেছি, "ম্যালোক কি পুনরায় প্রবেশকারী?"
আমার ধারণা ছিল যে সমস্ত পুনরায় প্রবেশকারী থ্রেড-নিরাপদ।
এই ধারণাটি কি ভুল?
সম্প্রতি, আমি "ম্যালোক থ্রেড নিরাপদ?" শিরোনাম সহ একটি প্রশ্ন জিজ্ঞাসা করেছি ? , এবং এর ভিতরে আমি জিজ্ঞাসা করেছি, "ম্যালোক কি পুনরায় প্রবেশকারী?"
আমার ধারণা ছিল যে সমস্ত পুনরায় প্রবেশকারী থ্রেড-নিরাপদ।
এই ধারণাটি কি ভুল?
উত্তর:
পুনরায় প্রবেশকারী ফাংশনগুলি গ্লোবাল ভেরিয়েবলগুলির উপর নির্ভর করে না যা সি লাইব্রেরির শিরোনামগুলিতে প্রকাশিত হয় .. স্ট্রটোক () বনাম strtok_r () উদাহরণস্বরূপ সি তে নিন take
কিছু ক্রিয়াকলাপের জন্য 'কাজ চলছে' সংরক্ষণের জন্য একটি জায়গা প্রয়োজন, পুনরায় প্রবেশকারী ফাংশনগুলি আপনাকে বৈশ্বিক ক্ষেত্রে নয়, থ্রেডের নিজস্ব স্টোরেজের মধ্যে এই পয়েন্টারটি নির্দিষ্ট করতে দেয়। যেহেতু এই স্টোরেজটি কলিং ফাংশনটির জন্য একচেটিয়া, তাই এটি বাধাগ্রস্থ ও পুনরায় প্রবেশ করা যেতে পারে (পুনরায় প্রবেশকারী) এবং যেহেতু বেশিরভাগ ক্ষেত্রে এই কাজ করার জন্য ফাংশন প্রয়োগগুলি প্রয়োজন হয় না তার বাইরে পারস্পরিক বর্জনীয় হয়, এগুলি প্রায়শই বিবেচিত হয় শংকা মুক্ত । এটি সংজ্ঞা অনুসারে গ্যারান্টিযুক্ত নয়।
এরনো তবে পসিক্স সিস্টেমে কিছুটা আলাদা কেস (এবং কীভাবে এটি সমস্ত কাজ করে তার কোনও ব্যাখ্যাতে অডবোল হতে পারে) :)
সংক্ষেপে, প্রবর্তকের প্রায়শই অর্থ থ্রেড নিরাপদ (যেমন "আপনি থ্রেড ব্যবহার করছেন তবে সেই ফাংশনের পুনরায় সংস্করণ ব্যবহার করুন"), তবে থ্রেড নিরাপদ মানে সর্বদা পুনরায় প্রবেশকারী (বা বিপরীত) হয় না। আপনি যখন থ্রেড-সুরক্ষার দিকে লক্ষ্য রাখছেন, তখন সম্মতি হ'ল আপনার কী চিন্তা করা উচিত। যদি কোনও ফাংশনটি ব্যবহার করতে আপনাকে লকিং এবং পারস্পরিক বর্জনের কোনও মাধ্যম সরবরাহ করতে হয় তবে ফাংশনটি সহজাতভাবে থ্রেড-নিরাপদ নয়।
তবে, সমস্ত ফাংশনগুলির জন্য উভয়ই পরীক্ষা করার প্রয়োজন হয় না। malloc()
প্রেরণকারী হওয়ার কোনও দরকার নেই, এটি কোনও প্রদত্ত থ্রেডের (এবং এটি নিজেই থ্রেড নিরাপদ) জন্য এন্ট্রি পয়েন্টের বাইরে থাকা কোনও কিছুর উপর নির্ভর করে না।
স্থিতিযুক্ত বরাদ্দকৃত মানগুলি ফাংশনগুলি মুটেক্স, ফিউটেক্স বা অন্যান্য পারমাণবিক লকিং প্রক্রিয়া ব্যবহার না করে থ্রেড নিরাপদ নয় । তবুও, তাদের বাধা দেওয়ার দরকার নেই যদি তাদের বাধা দেওয়া না হয়।
অর্থাত:
static char *foo(unsigned int flags)
{
static char ret[2] = { 0 };
if (flags & FOO_BAR)
ret[0] = 'c';
else if (flags & BAR_FOO)
ret[0] = 'd';
else
ret[0] = 'e';
ret[1] = 'A';
return ret;
}
সুতরাং, যেমন আপনি দেখতে পাচ্ছেন, একাধিক থ্রেড ব্যবহার করা যে কোনও ধরণের লক ছাড়াই একটি বিপর্যয় হতে পারে .. তবে এটি পুনরায় প্রবেশের কোনও উদ্দেশ্য নেই। যখন কিছু এম্বেড থাকা প্ল্যাটফর্মে গতিশীলভাবে বরাদ্দ করা মেমরিটি নিষিদ্ধ থাকে আপনি তখন তা চালিয়ে যাবেন।
খাঁটি কার্যকরী প্রোগ্রামিংয়ে, ভাড়াটে প্রায়ই থ্রেড নিরাপদ বোঝায় না , এটি ফাংশন এন্ট্রি পয়েন্ট, পুনরাবৃত্তি ইত্যাদিতে পাস করা সংজ্ঞায়িত বা বেনামে ফাংশনগুলির আচরণের উপর নির্ভর করে would
'থ্রেড নিরাপদ' রাখার একটি আরও ভাল উপায় সমবর্তী অ্যাক্সেসের জন্য নিরাপদ , যা প্রয়োজনের আরও ভাল চিত্রিত করে।
টিএল; ডিআর: একটি ফাংশন উভয়ই বা উভয়ই হতে পারে না, থ্রেড-নিরাপদ ent
থ্রেড-সুরক্ষা এবং পুনরায় পুনর্বিবেচনার জন্য উইকিপিডিয়া নিবন্ধগুলি পড়া ভাল। এখানে কয়েকটি উদ্ধৃতি দেওয়া হল:
একটি ফাংশন থ্রেড-নিরাপদ যদি:
এটি কেবল এমনভাবে ভাগ করা ডেটা স্ট্রাকচারগুলিকে ম্যানিপুলেট করে যা একই সাথে একাধিক থ্রেড দ্বারা নিরাপদ প্রয়োগের গ্যারান্টি দেয়।
একটি ফাংশন যদি অনুতপ্ত হয় তবে:
এটি কার্যকর করার সময় যে কোনও সময়ে বাধা দেওয়া যায় এবং এরপরে পূর্বেকার অনুরোধগুলি সম্পূর্ণরূপে কার্যকর হওয়ার আগে নিরাপদে আবার ("পুনরায় প্রবেশ") নামে ডাকা হয়।
সম্ভাব্য পুনঃপ্রবেশের উদাহরণ হিসাবে, উইকিপিডিয়া সিস্টেম বিঘ্ন দ্বারা কল করার জন্য ডিজাইন করা একটি ফাংশনের উদাহরণ দেয়: মনে করুন যে অন্য কোনও বাধা ঘটলে এটি ইতিমধ্যে চলছে। তবে আপনি কেবল সিস্টেমের বিঘ্নগুলির সাথে কোড না করার কারণে আপনি নিরাপদ বলে মনে করবেন না: আপনি যদি কলব্যাকস বা পুনরাবৃত্তি ফাংশন ব্যবহার করেন তবে একক থ্রেডেড প্রোগ্রামে আপনাকে পুনরায় সমস্যা হতে পারে।
বিভ্রান্তি এড়ানোর মূল চাবিকাঠিটি হ'ল প্রতিবর্তক কেবল একটি থ্রেড এক্সিকিউটিভকে বোঝায়। মাল্টিটাস্কিং অপারেটিং সিস্টেমের অস্তিত্ব ছিল না এমন সময় থেকেই এটি একটি ধারণা।
উদাহরণ
(উইকিপিডিয়া নিবন্ধ থেকে কিছুটা সংশোধিত)
উদাহরণ 1: থ্রেড-নিরাপদ নয়, তদন্তকারী নয়
/* As this function uses a non-const global variable without
any precaution, it is neither reentrant nor thread-safe. */
int t;
void swap(int *x, int *y)
{
t = *x;
*x = *y;
*y = t;
}
উদাহরণ 2: থ্রেড-নিরাপদ, তদন্তকারী নয়
/* We use a thread local variable: the function is now
thread-safe but still not reentrant (within the
same thread). */
__thread int t;
void swap(int *x, int *y)
{
t = *x;
*x = *y;
*y = t;
}
উদাহরণ 3: থ্রেড-নিরাপদ নয়, প্রেরণকারী
/* We save the global state in a local variable and we restore
it at the end of the function. The function is now reentrant
but it is not thread safe. */
int t;
void swap(int *x, int *y)
{
int s;
s = t;
t = *x;
*x = *y;
*y = t;
t = s;
}
উদাহরণ 4: থ্রেড-সেফ, প্রেরণকারী
/* We use a local variable: the function is now
thread-safe and reentrant, we have ascended to
higher plane of existence. */
void swap(int *x, int *y)
{
int t;
t = *x;
*x = *y;
*y = t;
}
t = *x
, কল করে swap()
, তবে t
ওভাররাইড হয়ে যাবে, যার ফলে অপ্রত্যাশিত ফলাফলের দিকে যায়।
swap(5, 6)
বাধাগ্রস্থ হওয়ার জন্য বিবেচনা করুন swap(1, 2)
। পরে t=*x
, s=t_original
এবং t=5
। এখন, বাধা পরে, s=5
এবং t=1
। যাইহোক, দ্বিতীয় swap
রিটার্নের আগে এটি প্রেক্ষাপট, তৈরি করে পুনরুদ্ধার করবে t=s=5
। এখন আমরা প্রথম ফিরে যেতে swap
সঙ্গে t=5 and s=t_original
এবং পরে অবিরত t=*x
। সুতরাং, ফাংশনটি আবার প্রবেশকারী হিসাবে উপস্থিত হবে না। মনে রাখবেন যে প্রতিটি কল s
স্ট্যাকের জন্য বরাদ্দকৃত নিজস্ব কপি পায় ।
এটি সংজ্ঞা উপর নির্ভর করে। উদাহরণস্বরূপ কিউটি নিম্নলিখিতটি ব্যবহার করে:
আমন্ত্রণগুলি ভাগ করা ডেটা ব্যবহার করার পরেও একাধিক থ্রেড থেকে এক সাথে থ্রেড-সেফ * ফাংশন বলা যেতে পারে, কারণ ভাগ করা ডেটার সমস্ত রেফারেন্স সিরিয়ালযুক্ত ized
একাধিক থ্রেড থেকে একই সাথে একটি পুনরায় প্রেরণকারী ফাংশনও বলা যেতে পারে, তবে কেবলমাত্র প্রতিটি অনুরোধটির নিজস্ব ডেটা ব্যবহার করা হয়।
অতএব, একটি থ্রেড-নিরাপদ ফাংশন সর্বদা তিরস্কারকারী, তবে একটি পুনরায় প্রেরণকারী ফাংশন সর্বদা থ্রেড-নিরাপদ থাকে না।
এক্সটেনশন দ্বারা, কোনও শ্রেণীর পুনরায় অনুগ্রহ করে বলা হয় যদি এর সদস্য ফাংশনগুলি একাধিক থ্রেড থেকে নিরাপদে কল করা যায়, যতক্ষণ না প্রতিটি থ্রেড শ্রেণীর আলাদা উদাহরণ ব্যবহার করে। শ্রেণীর থ্রেড-নিরাপদ যদি এর সদস্য ফাংশনগুলি একাধিক থ্রেড থেকে নিরাপদে কল করা যায়, এমনকি সমস্ত থ্রেড শ্রেণীর একই উদাহরণ ব্যবহার করে।
তবে তারাও সাবধান:
দ্রষ্টব্য: মাল্টিথ্রেডিং ডোমেনের টার্মিনোলজি পুরোপুরি মানকৃত নয়। পসআইএক্স প্রবর্তক এবং থ্রেড-সেফের সংজ্ঞা ব্যবহার করে যা এর সিআইপিগুলির জন্য কিছুটা আলাদা। Qt সহ অন্যান্য অবজেক্ট-ভিত্তিক সি ++ শ্রেণির পাঠাগারগুলি ব্যবহার করার সময়, সংজ্ঞাগুলি বোঝা গেছে তা নিশ্চিত হয়ে নিন।