সি ++ এ থ্রেডগুলির মধ্যে দ্রুত বার্তাটি পাস করার জন্য মেমরি পরিচালনা


9

ধরুন এখানে দুটি থ্রেড রয়েছে, যা একে অপরকে সংশ্লেষে ডেটা বার্তা প্রেরণ করে যোগাযোগ করে। প্রতিটি থ্রেডে একরকম ম্যাসেজের সারি থাকে।

আমার প্রশ্নটি খুব নিম্ন স্তরের: মেমরিটি পরিচালনা করার সবচেয়ে কার্যকর উপায়টি কী হতে পারে বলে আশা করা যায়? আমি বেশ কয়েকটি সমাধান সম্পর্কে ভাবতে পারি:

  1. প্রেরক এর মাধ্যমে বস্তুটি তৈরি করে new। রিসিভার কল delete
  2. মেমরি পুলিং (মেমোরিটিকে প্রেরকের কাছে ফিরিয়ে দিতে)
  3. আবর্জনা সংগ্রহ (যেমন, বোহেম জিসি)
  4. (যদি বস্তুগুলি যথেষ্ট ছোট হয়) সম্পূর্ণরূপে গাদা বরাদ্দ এড়াতে মান দ্বারা অনুলিপি করুন

1) সর্বাধিক সুস্পষ্ট সমাধান, তাই আমি এটি প্রোটোটাইপের জন্য ব্যবহার করব। সম্ভাবনাগুলি এটি ইতিমধ্যে যথেষ্ট ভাল good তবে আমার নির্দিষ্ট সমস্যা থেকে স্বতন্ত্র, আমি অবাক হই যে আপনি যদি পারফরম্যান্সের জন্য অনুকূল হন তবে কোন কৌশলটি সবচেয়ে প্রতিশ্রুতিবদ্ধ।

আমি পুলিং তাত্ত্বিকভাবে সর্বোত্তম হওয়ার প্রত্যাশা করব, বিশেষত কারণ আপনি থ্রেডগুলির মধ্যে তথ্যের প্রবাহ সম্পর্কে অতিরিক্ত জ্ঞান ব্যবহার করতে পারেন। যাইহোক, আমি আশঙ্কা করি যে এটি সঠিক হওয়াও সবচেয়ে কঠিন। প্রচুর টিউনিং ... :-(

জঞ্জাল সংগ্রহের পরে যোগ করা বেশ সহজ হওয়া উচিত (সমাধান 1 পরে), এবং আমি এটি খুব ভাল সঞ্চালনের আশা করব। সুতরাং, আমি অনুমান করি যে 1) যদি খুব অকার্যকর হয়ে পড়ে তবে এটি সবচেয়ে কার্যকর সমাধান।

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

উত্তর:


9

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

যদি আপনি একটি উপরের গণ্ডির পূর্বাভাস করতে পারেন char buf[256], উদাহরণস্বরূপ একটি ব্যবহারিক বিকল্প যদি আপনি না করতে পারেন যা কেবল বিরল ক্ষেত্রে কেবল স্তরের বরাদ্দকেই আহবান করতে পারে:

struct Message
{
    // Stores the message data.
    char buf[256];

    // Points to 'buf' if it fits, heap otherwise.
    char* data;
};

3

আপনি কীভাবে সারিগুলি প্রয়োগ করবেন তার উপর নির্ভর করে এটি।

আপনি যদি অ্যারে (রাউন্ড রবিন স্টাইল) নিয়ে যান তবে সমাধানের জন্য আপনার আকারের উপরের বাউন্ড স্থাপন করতে হবে you আপনি যদি কোনও লিঙ্কযুক্ত সারিতে যান তবে আপনার বরাদ্দকৃত বস্তুগুলির প্রয়োজন।

এর পরে, সম্পদ পুলিং সহজে কাজ করা যেতে পারে যখন আপনি শুধু নতুন প্রতিস্থাপন এবং মুছতে AllocMessage<T>এবং freeMessage<T>। আমার পরামর্শটি Tহ'ল কংক্রিট বরাদ্দ করার সময় সম্ভাব্য আকারগুলি কত পরিমাণে থাকতে পারে তা সীমাবদ্ধ করে দেওয়া messages

সোজা আপ আবর্জনা সংগ্রহ কাজ করতে পারে তবে এটি যখন বড় অংশ সংগ্রহ করার প্রয়োজন হয় তখন দীর্ঘ বিরতি সৃষ্টি করতে পারে এবং নতুন / মুছার চেয়ে কিছুটা খারাপ সম্পাদন করবে (আমি মনে করি)।


3

এটি যদি সি ++ তে থাকে তবে কেবল একটি স্মার্ট পয়েন্টার ব্যবহার করুন - অনন্য_প্টার আপনার পক্ষে ভাল কাজ করবে কারণ এটি অন্তর্নিহিত অবজেক্টটিকে মুছে ফেলবে না যতক্ষণ না কারওর উপর এটির হাতল না থাকে। আপনি পিটিআর অবজেক্টটি রিসিভারের কাছে মূল্য দিয়ে পাস করেন এবং কখনই কোন থ্রেডটি মুছে ফেলা উচিত তা নিয়ে চিন্তা করার দরকার নেই (ক্ষেত্রে যখন রিসিভারটি বস্তুটি গ্রহণ করে না)।

আপনার এখনও থ্রেডগুলির মধ্যে লকিং পরিচালনা করতে হবে তবে কোনও স্মৃতি কপি না হওয়ার কারণে পারফরম্যান্স ভাল হবে (কেবলমাত্র পিটিআর অবজেক্ট নিজেই ক্ষুদ্র)।

স্তূপে মেমরি বরাদ্দ করা এখন পর্যন্ত দ্রুততম জিনিস নয়, তাই এটিকে আরও দ্রুত করতে পুলিং ব্যবহার করা হয়। আপনি একটি পুলের প্রাক-আকারের গাদা থেকে কেবল পরবর্তী ব্লকটি ধরুন, সুতরাং এটির জন্য কেবল একটি বিদ্যমান লাইব্রেরি ব্যবহার করুন।


2
লক করা মেমরি কপি করার চেয়ে সাধারণত অনেক বড় সমস্যা। এমনি বলছি.
tmadmers

আপনি যখন লিখবেন unique_ptr, আমি অনুমান করেছি আপনি বোঝাতে চাইছেন shared_ptr। তবে কোনও সন্দেহ নেই যে স্মার্ট পয়েন্টার ব্যবহার সম্পদ পরিচালনার জন্য ভাল, আপনি মেমরির বরাদ্দ এবং অবনতির কিছু ফর্ম ব্যবহার করছেন তা সত্য নয়। আমি মনে করি এই প্রশ্নটি আরও নিম্ন-স্তরের।
5gon12eder

3

কোনও থ্রেড থেকে অন্য থ্রেডে যোগাযোগ করার সময় সবচেয়ে বড় পারফরম্যান্স হিট হ'ল লক ধরার ওভারহেড। এটি বেশ কয়েকটি মাইক্রোসেকেন্ডের ক্রম অনুসারে, যা একজোড়া new/ deleteগ্রহণের গড় সময়ের চেয়ে একশত বেশি (একশ ন্যানোসেকেন্ডের ক্রম অনুসারে)। বুদ্ধিমান newবাস্তবায়নগুলি তাদের কার্যকারিতা হিট এড়াতে প্রায় সমস্ত ব্যয়ে লক এড়ানোর চেষ্টা করে।

এটি বলেছিল, আপনি নিশ্চিত করতে চান যে কোনও থ্রেড থেকে অন্য থ্রেডে যোগাযোগ করার সময় আপনাকে লকগুলি ধরার দরকার নেই। আমি এটি অর্জনের দুটি সাধারণ পদ্ধতি জানি। দু'জনই কেবল একজন প্রেরক এবং একজন প্রাপকের মধ্যে একীকরণমূলক কাজ করে:

  1. একটি রিং বাফার ব্যবহার করুন। উভয় প্রক্রিয়া এই বাফারে একটি পয়েন্টারকে নিয়ন্ত্রণ করে, একটি হ'ল পঠিত পয়েন্টার, অন্যটি রাইট পয়েন্টার।

    • প্রেরক প্রথমে যাচাই করে পয়েন্টারগুলির সাথে তুলনা করে কোনও উপাদান যুক্ত করার জায়গা আছে কিনা, তারপরে উপাদানটি যুক্ত করুন, তারপরে লেখার পয়েন্টারটি বাড়িয়ে দিন।

    • গ্রাহকরা পয়েন্টারগুলির সাথে তুলনা করে পড়ার জন্য কোনও উপাদান আছে কিনা তা পরীক্ষা করে, তারপরে উপাদানটি পড়ে, তারপরে পয়েন্ট পয়েন্টারটি বাড়িয়ে দেয়।

    পয়েন্টারগুলিকে থ্রেডের মধ্যে ভাগ করা হওয়ায় এটমিক্যাল হওয়া দরকার। যাইহোক, প্রতিটি পয়েন্টার কেবল একটি থ্রেড দ্বারা সংশোধিত হয়, অন্যটির পয়েন্টারটিতে কেবল পঠন অ্যাক্সেসের প্রয়োজন। বাফারের উপাদানগুলি নিজেরাই পয়েন্টার হতে পারে, যা আপনাকে সহজেই আপনার রিং বাফারকে এমন আকারে আকার দিতে দেয় যা প্রেরককে ব্লক করে না।

  2. একটি লিঙ্কযুক্ত তালিকা ব্যবহার করুন যাতে সর্বদা কমপক্ষে একটি উপাদান থাকে। প্রাপকের প্রথম উপাদানটির একটি পয়েন্টার রয়েছে, প্রেরকের শেষ উপাদানটির একটি পয়েন্টার রয়েছে। এই পয়েন্টার ভাগ করা হয় না।

    • প্রেরক লিঙ্কযুক্ত তালিকার জন্য এটির nextনির্দেশককে সেট করে একটি নতুন নোড তৈরি করে nullptr। তারপরে এটি nextনতুন উপাদানকে নির্দেশ করতে শেষ উপাদানটির পয়েন্টার আপডেট করে । শেষ পর্যন্ত, এটি নতুন উপাদানটিকে তার নিজস্ব পয়েন্টারে সঞ্চয় করে।

    • রিসিভার nextনতুন উপাদান উপলব্ধ কিনা তা দেখতে প্রথম উপাদানটির পয়েন্টার দেখেন। যদি তা হয় তবে এটি পুরানো প্রথম উপাদানটি মুছে ফেলে, নিজস্ব উপাদানটিকে বর্তমান উপাদানটির দিকে নির্দেশ করতে অগ্রসর হয় এবং এটি প্রক্রিয়াজাতকরণ শুরু করে।

    এই সেটআপে, nextপয়েন্টারগুলি পরমাণু হওয়া দরকার, এবং প্রেরককে অবশ্যই তার nextপয়েন্টারটি সেট করার পরে দ্বিতীয় শেষ উপাদানটিকে অবহেলা না করার বিষয়ে নিশ্চিত হতে হবে । অবশ্যই সুবিধাটি হ'ল প্রেরককে কখনও অবরুদ্ধ করতে হবে না।

উভয় পদ্ধতির কোনও লক-ভিত্তিক পদ্ধতির চেয়ে অনেক দ্রুত, তবে সঠিক হওয়ার জন্য তাদের সাবধানতার সাথে বাস্তবায়ন প্রয়োজন। এবং, অবশ্যই, তাদের পয়েন্টার রাইটিং / বোঝার নেটিভ হার্ডওয়্যার পারমাণবিকতা প্রয়োজন; যদি আপনার atomic<>প্রয়োগটি অভ্যন্তরীণভাবে একটি লক ব্যবহার করে তবে আপনি বেশ ক্ষতিগ্রস্থ হন।

তেমনি, আপনার বেশ কয়েকটি পাঠক এবং / বা লেখক থাকলে, আপনি প্রায় ধ্বংসপ্রাপ্ত: আপনি একটি লক-কম স্কিম নিয়ে আসতে চেষ্টা করতে পারেন, তবে এটি কার্যকরভাবে কার্যকর করা জটিল। এই পরিস্থিতিগুলি একটি লক দিয়ে পরিচালনা করা অনেক সহজ। যাইহোক, একবার আপনি কোনও লক ধরে ফেললে আপনি new/ deleteপারফরম্যান্স নিয়ে চিন্তিত হওয়া বন্ধ করতে পারেন ।


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