কাউট সিঙ্ক্রোনাইজ / থ্রেড-নিরাপদ?


112

সাধারণভাবে আমি ধরে নিয়েছি যে স্ট্রিমগুলি সিঙ্ক্রোনাইজ করা হয়নি, উপযুক্ত লকিং এটি ব্যবহারকারীর উপর নির্ভর করে। তবে, coutস্ট্যান্ডার্ড লাইব্রেরিতে বিশেষ চিকিত্সা পাওয়ার মতো জিনিসগুলি কী?

অর্থাত্ যদি একাধিক থ্রেড লিখতে থাকে তবে coutতারা coutকী বস্তুটিকে দূষিত করতে পারে ? আমি বুঝতে পারি যে সিঙ্ক্রোনাইজ করা হলেও আপনি এখনও এলোমেলোভাবে আন্তঃবাহিত আউটপুট পেতে পারেন তবে এটি ইন্টারলিভিংয়ের গ্যারান্টিযুক্ত। অর্থাৎ, coutএকাধিক থ্রেড থেকে এটি নিরাপদ ?

এই বিক্রেতা কি নির্ভরশীল? জিসিসি কি করে?


গুরুত্বপূর্ণ : আপনি যদি "হ্যাঁ" বলে থাকেন তবে আপনার উত্তরটির জন্য দয়া করে কোনও প্রকারের রেফারেন্স সরবরাহ করুন কারণ এর কোনও প্রমানের আমার প্রমাণ প্রয়োজন।

আমার উদ্বেগ অন্তর্নিহিত সিস্টেম কলগুলি সম্পর্কে নয়, সেগুলি ভাল, তবে স্ট্রিমগুলি শীর্ষে বাফারিংয়ের একটি স্তর যুক্ত করে।


2
এটি বিক্রেতা নির্ভর। সি ++ (সি ++ 0x এর আগে) একাধিক থ্রেডের ধারণা নেই।
সোভেন

2
সি ++ 0 এক্স সম্পর্কে কী? এটি একটি মেমরির মডেলটি সংজ্ঞায়িত করে এবং একটি থ্রেড কী, তাই সম্ভবত এই জিনিসগুলি আউটপুটটিতে পড়ে?
রুবেনভবি

2
এমন কোনও বিক্রেতারা আছেন যা এটিকে থ্রেড-নিরাপদ করে?
এডিএ-কিএ মার্ট-ওরা-y

সবচেয়ে সাম্প্রতিক সি ++ ২০১১ প্রস্তাবিত স্ট্যান্ডার্ডটির সাথে কারও লিংক আছে?
এডিএ-কিএ মার্ট-ওরা-y

4
সম্পূর্ণরূপে আউটপুট এক শটে লেখা হওয়ায় এটি কিছুটা অর্থেই printfজ্বলজ্বল করে stdout; std::coutএক্সপ্রেশন চেইনের প্রতিটি লিঙ্ক ব্যবহার করার সময় পৃথকভাবে আউটপুট হবে stdout; তাদের মধ্যবর্তী সময়ে আরও কিছু থ্রেড রাইটিং থাকতে stdoutপারে যার কারণে চূড়ান্ত আউটপুট ক্রমটি গোলমাল হয়ে যায়।
কিংবদন্তি 2 কে

উত্তর:


106

সি ++ 03 স্ট্যান্ডার্ড এটি সম্পর্কে কিছুই বলে না। কোনও কিছুর থ্রেড-সুরক্ষা সম্পর্কে আপনার যখন কোনও গ্যারান্টি নেই তখন আপনার এটি থ্রেড-নিরাপদ হিসাবে বিবেচনা করা উচিত।

এখানে বিশেষ আগ্রহের বিষয়টি coutহল বাফার করা। এমনকি যদি কলগুলিতে write(বা এটি যে কোনও কিছু সেই নির্দিষ্ট প্রয়োগের ক্ষেত্রে সেই প্রভাবটি সম্পাদন করে) পারস্পরিক একচেটিয়া হওয়ার নিশ্চয়তা দেওয়া হয়, তবে বাফারটি বিভিন্ন থ্রেড দ্বারা ভাগ করা যেতে পারে। এটি দ্রুত স্রোতের অভ্যন্তরীণ অবস্থার দুর্নীতির দিকে পরিচালিত করবে।

এমনকি যদি বাফার অ্যাক্সেসকে থ্রেড-সেফ হওয়ার গ্যারান্টিযুক্ত করা হয় তবে এই কোডটিতে কী ঘটবে বলে আপনি মনে করেন?

// in one thread
cout << "The operation took " << result << " seconds.";

// in another thread
cout << "Hello world! Hello " << name << "!";

আপনি সম্ভবত এখানে প্রতিটি লাইন পারস্পরিক বর্জন কাজ করতে চান। তবে কীভাবে একটি বাস্তবায়ন গ্যারান্টি দিতে পারে?

সি ++ 11 এ আমাদের কিছু গ্যারান্টি রয়েছে। এফডিআইএস §27.4.1 [iostream.objects.overview] এ নিম্নলিখিতটি বলেছে:

একটি সিঙ্ক্রোনাইজড (§27.5.3.4) স্ট্যান্ডার্ড আইস্ট্রিম অবজেক্টের ফর্ম্যাট এবং অপর্যাপ্ত ফর্ম ইনপুট (§27.7.2.1) এবং আউটপুট (§27.7.3.1) ফাংশন বা একাধিক থ্রেড দ্বারা একটি স্ট্যান্ডার্ড সি স্ট্রিমের জন্য কোনও ডেটা রেসের ফলশ্রুতি হবে না (§ 1.10)। [দ্রষ্টব্য: ব্যবহারকারীরা ইন্টারলিভ অক্ষরগুলি এড়াতে চান তবে তাদের অবশ্যই একাধিক থ্রেড দ্বারা এই অবজেক্টগুলি এবং স্ট্রিমগুলির একসাথে ব্যবহারের সমন্বয় করতে হবে। - শেষ নোট]

সুতরাং, আপনি কলুষিত স্ট্রিম পাবেন না, তবে আপনি যদি আউটপুট আবর্জনা না চান তবে আপনাকে সেগুলি ম্যানুয়ালি সিঙ্ক্রোনাইজ করতে হবে।


2
সি ++ 98 / সি ++ 03 এর জন্য প্রযুক্তিগতভাবে সত্য, তবে আমি মনে করি সবাই এটি জানেন। তবে এটি দুটি আকর্ষণীয় প্রশ্নের উত্তর দেয় না: সি ++ 0 এক্স সম্পর্কে কী? সাধারণ বাস্তবায়ন আসলে কী করে ?
নিমো

1
@ এডিএ-কিএ মার্ট-ওরা-ওয়াই: না, আপনার এটির ভুল আছে। সি ++ 11 পরিষ্কারভাবে সংজ্ঞায়িত যে আদর্শ প্রবাহ বস্তু করতে সিঙ্ক্রোনাইজ করা এবং ভাল-সংজ্ঞায়িত আচরণ বজায় রাখা, না যে সেগুলি ডিফল্টভাবে এমন।
iljarn

12
@ildjarn - না, @ এডিএ-কিএ মর্ট-ওরা-ওয়াই সঠিক। যতক্ষণ cout.sync_with_stdio()সত্য, coutঅতিরিক্ত সিঙ্ক্রোনাইজেশন ছাড়াই একাধিক থ্রেড থেকে অক্ষরগুলি আউটপুট ব্যবহার করা ভালভাবে সংজ্ঞায়িত করা হয় তবে কেবলমাত্র পৃথক বাইটের স্তরে। সুতরাং, cout << "ab";এবং cout << "cd"বিভিন্ন থ্রেডে মৃত্যুদন্ড কার্যকর করা যেতে পারে acdb, উদাহরণস্বরূপ, তবে অপরিবর্তিত আচরণের কারণ নাও হতে পারে।
জোহানেসড

4
@ জোহানেসডি: আমরা সেখানে চুক্তিতে রয়েছি - এটি অন্তর্নিহিত সি এপিআইয়ের সাথে সিঙ্ক্রোনাইজ হয়েছে। আমার বক্তব্যটি হ'ল এটি কার্যকর উপায়ে "সিঙ্ক্রোনাইজড" নয়, অর্থাত্ আবর্জনা ডেটা না চাইলে একটি এখনও ম্যানুয়াল সিঙ্ক্রোনাইজেশন প্রয়োজন।
iljarn

2
@ জিল্ডার্ন, আমি আবর্জনার ডেটা নিয়ে ঠিক আছি, যা আমি বুঝতে পারি। আমি কেবল ডেটা রেসের শর্তে আগ্রহী, যা এখন পরিষ্কার বলে মনে হচ্ছে।
এডিএ-কিএ মার্ট-ওরা-y

16

এটা একটা ভাল প্রশ্ন.

প্রথমত, সি ++ 98 / সি ++ 03 এর "থ্রেড" ধারণা নেই। সুতরাং সেই বিশ্বে প্রশ্নটি অর্থহীন।

সি ++ 0 এক্স সম্পর্কে কী? দেখুন Martinho এর উত্তর (যা আমি আমাকে বিস্মিত মানা)।

নির্দিষ্ট বাস্তবায়নগুলি প্রাক-সি ++ 0x সম্পর্কে কীভাবে? ঠিক আছে, উদাহরণস্বরূপ, এখানে basic_streambuf<...>:sputcজিসিসি 4.5.2 ("স্ট্র্যামবুফ" শিরোনাম) এর উত্স কোডটি রয়েছে :

 int_type
 sputc(char_type __c)
 {
   int_type __ret;
   if (__builtin_expect(this->pptr() < this->epptr(), true)) {
       *this->pptr() = __c;
        this->pbump(1);
        __ret = traits_type::to_int_type(__c);
      }
    else
        __ret = this->overflow(traits_type::to_int_type(__c));
    return __ret;
 }

স্পষ্টতই, এটি কোনও লকিং সম্পাদন করে না। এবং না xsputn। এবং এটি অবশ্যই স্ট্র্যামবুফের ধরণ যা কোট ব্যবহার করে।

আমি যতদূর বলতে পারি, libstdc ++ স্ট্রিম ক্রিয়াকলাপের মধ্যে কোনও লকিং সম্পাদন করে না। এবং আমি কোনও আশা করব না, কারণ এটি ধীর হবে।

তাই এই বাস্তবায়ন অবশ্যই এটিকে দুটি থ্রেড 'আউটপুট সম্ভব অন্যান্য প্রতিটি দুর্নীতিগ্রস্ত (হয় না শুধু ইন্টারলিভ)।

এই কোড ডেটা কাঠামো নিজেই দূষিত করতে পারে? উত্তর এই ফাংশনগুলির সম্ভাব্য মিথস্ক্রিয়াগুলির উপর নির্ভর করে; উদাহরণস্বরূপ, যদি একটি থ্রেড বাফারটি ফ্লাশ করার চেষ্টা করে তবে অন্য একটি কল করতে xsputnবা যা কিছু করার চেষ্টা করে happens এটি আপনার সংকলক এবং সিপিইউ মেমরির লোড এবং স্টোরগুলিকে পুনঃক্রম করতে কীভাবে সিদ্ধান্ত নেয় তার উপর নির্ভর করে; এটি নিশ্চিত হতে একটি সাবধানী বিশ্লেষণ লাগবে। যদি দুটি থ্রেড একই স্থানে একই জায়গায় পরিবর্তন করার চেষ্টা করে তবে আপনার সিপিইউ কী করবে তাও নির্ভর করে।

অন্য কথায়, আপনার বর্তমান পরিবেশে এটি ঠিকঠাক কাজ করার পরেও, আপনি যখন আপনার রানটাইম, সংকলক বা সিপিইউ আপডেট করেন তখন এটি ভেঙে যেতে পারে।

এক্সিকিউটিভ সংক্ষিপ্তসার: "আমি না"। লগিং ক্লাস তৈরি করুন যা যথাযথ লকিং করে বা C ++ 0x এ চলেছে।

একটি দুর্বল বিকল্প হিসাবে, আপনি unfuffered যাও চকচকে সেট করতে পারে। এটি সম্ভবত (যদিও গ্যারান্টিযুক্ত নয়) যা বাফারের সাথে সম্পর্কিত সমস্ত যুক্তি এড়িয়ে যাবে এবং writeসরাসরি কল করবে । যদিও এটি নিষিদ্ধভাবে ধীর হতে পারে।


1
উত্তম উত্তর, তবে মার্টিনহোর প্রতিক্রিয়াটি দেখুন যা দেখায় যে সি ++ 11 এর জন্য সিঙ্ক্রোনাইজেশন সংজ্ঞায়িত করে cout
এডিএ-কিএ মার্ট-ওরা-ই

7

সি ++ স্ট্যান্ডার্ড স্ট্রিমগুলিতে লেখা থ্রেড-নিরাপদ কিনা তা নির্দিষ্ট করে না তবে সাধারণত তা হয় না।

www.techrepublic.com/article/use-stl-streams-for-easy-c-plus-plus-thread-safe-logging

এবং এছাড়াও: সি ++ থ্রেড-নিরাপদ (কোট, সেরার, ক্লগ) এ স্ট্যান্ডার্ড আউটপুট স্ট্রিমগুলি রয়েছে?

হালনাগাদ

নতুন স্ট্যান্ডার্ড সি ++ 11 এ সম্পর্কে কী জানায় তা জানতে দয়া করে @ মার্টিনহো ফার্নান্দেসের জবাবটি দেখুন।


3
আমি অনুমান করি যেহেতু সি ++ 11 এখন এই উত্তরটি আসলে ভুল actually
এডিএ-কিএ মর্ট-ওরা-y

6

অন্যান্য উত্তরের হিসাবে উল্লেখ করা হয়েছে, এটি অবশ্যই বিক্রেতা-নির্দিষ্ট কারণ সি ++ স্ট্যান্ডার্ড থ্রেডিংয়ের কোনও উল্লেখ করেনি (সি ++ 0 এক্সে এই পরিবর্তন)।

থ্রেড সুরক্ষা এবং I / O সম্পর্কে জিসিসি সম্পূর্ণ প্রতিশ্রুতি দেয় না। তবে এটি যে প্রতিশ্রুতি দেয় তার ডকুমেন্টেশন এখানে রয়েছে:

মূল জিনিস সম্ভবত:

__Basic_file টাইপটি কেবল সি স্টিডিও স্তরটির চারপাশে ছোট ছোট মোড়কের সংগ্রহ (আবার স্ট্রাকচারের লিঙ্কটি দেখুন)। আমরা কোনও লকিং করি না, কেবল ফপেন, ফাইরাইট এবং আরও কিছুগুলিতে কল করতে পারি।

সুতরাং, for.০ এর জন্য, "আই / ও-র জন্য মাল্টিথ্রেডিং নিরাপদ" এই প্রশ্নের উত্তর অবশ্যই দেওয়া উচিত, "আপনার প্ল্যাটফর্মের সি লাইব্রেরি আই / ও-র জন্য থ্রেডসেফ?" কিছু ডিফল্টরূপে, কিছু না; থ্রেডফ্যাটি এবং দক্ষতার বিভিন্ন ট্রেড অফ সহ অনেকগুলি সি লাইব্রেরির একাধিক বাস্তবায়ন অফার করে। আপনাকে, প্রোগ্রামারটিকে সর্বদা একাধিক থ্রেড সহ যত্ন নেওয়া প্রয়োজন।

(উদাহরণস্বরূপ, পসিক্স স্ট্যান্ডার্ডের প্রয়োজন সি স্টিডিও ফাইল * অপারেশনগুলি পারমাণবিক P এক থ্রেডে fclose (fs) কল করার মতো বোকামি কাজ না করা এবং অন্যটিতে fs এর অ্যাক্সেস অনুসরণ করা)

সুতরাং, যদি আপনার প্ল্যাটফর্মের সি লাইব্রেরি থ্রেডসেফ হয়, তবে আপনার fstream I / O ক্রিয়াকলাপগুলি সর্বনিম্ন স্তরে থ্রেডসফেট হবে। উচ্চ-স্তরের ক্রিয়াকলাপগুলির জন্য, যেমন স্ট্রিম ফর্ম্যাটিং ক্লাসে থাকা ডেটা ম্যানিপুলেট করা (যেমন, একটি স্ট্যান্ড :: অফ স্ট্রিমের মধ্যে কলব্যাক সেটআপ করা), আপনাকে অন্য কোনও সমালোচিত শেয়ার্ড রিসোর্সের মতো এ্যাক্সেসগুলি রক্ষা করতে হবে।

আমি জানি না কিছু উল্লিখিত 3.0 টাইমফ্রেম সাইন পরিবর্তন করেছে কিনা।

এমএসভিসির থ্রেড সুরক্ষার ডকুমেন্টেশনগুলি iostreamsএখানে পাওয়া যাবে: http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx :

একক বস্তু একাধিক থ্রেড থেকে পড়ার জন্য থ্রেড নিরাপদ। উদাহরণস্বরূপ, একটি বস্তু এ দেওয়া, এক সাথে থ্রেড 1 এবং থ্রেড 2 থেকে এ পড়া নিরাপদ।

যদি কোনও এক থ্রেড দ্বারা কোনও একক অবজেক্ট রচনা করা হয়, তবে একই বা অন্যান্য থ্রেডগুলিতে সমস্ত বস্তু পড়তে এবং লিখতে হবে। উদাহরণস্বরূপ, একটি অবজেক্ট A দেওয়া হয়েছে, থ্রেড 1 যদি A কে লেখা হয় তবে থ্রেড 2 অবশ্যই A থেকে পড়তে বা লেখা থেকে আটকাতে হবে

অন্য থ্রেড একই ধরণের অন্য কোনও ইভেন্টে পড়তে বা লিখতে থাকলেও কোনও ধরণের একটি উদাহরণে পড়া এবং লিখতে নিরাপদ। উদাহরণস্বরূপ, একই ধরণের বস্তু A এবং B দেওয়া, এটি নিরাপদ যদি A থ্রেড 1 এ লেখা হয় এবং বি থ্রেড 2-এ পড়া হয়।

...

iostream ক্লাস

আইওস্ট্রিম ক্লাসগুলি একটি ব্যতিক্রম সহ অন্যান্য শ্রেণীর মতো একই নিয়ম অনুসরণ করে। একাধিক থ্রেড থেকে কোনও অবজেক্টে লেখা নিরাপদ। উদাহরণস্বরূপ, থ্রেড 1 একই সাথে থ্রেড 2-তে থ্রেড লিখতে পারে তবে যাইহোক, এর ফলে দুটি থ্রেড থেকে আউটপুট একে অপরকে মিলে যাবে।

দ্রষ্টব্য: একটি স্ট্রিম বাফার থেকে পঠন একটি রিড অপারেশন হিসাবে বিবেচনা করা হয় না। এটি একটি রাইটিং অপারেশন হিসাবে বিবেচনা করা উচিত, কারণ এটি শ্রেণীর অবস্থার পরিবর্তন করে।

নোট করুন যে তথ্যটি এমএসভিসির সাম্প্রতিকতম সংস্করণের জন্য (বর্তমানে ভিএস 2010 / এমএসভিসি 10 / cl.exe16.x এর জন্য)। আপনি পৃষ্ঠায় একটি ড্রপডাউন নিয়ন্ত্রণ ব্যবহার করে এমএসভিসির পুরানো সংস্করণগুলির জন্য তথ্য নির্বাচন করতে পারেন (এবং তথ্যটি পুরানো সংস্করণগুলির জন্য আলাদা)।


1
"আমি জানি না যে উল্লিখিত ৩.০ টাইমফ্রেমের কিছু পরিবর্তন হয়েছে কিনা।" এটা অবশ্যই করেছে। বিগত বেশ কয়েক বছর ধরে, g ++ স্ট্রিম প্রয়োগগুলি নিজস্ব বাফারিং সম্পাদন করেছে।
নিমো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.