এসটিডি :: অনন্য_লক <স্টাডি :: মিউটেক্স> বা এসডিডি: লক_গার্ড <স্টাডি :: মিটেক্স>?


348

আমার দুটি ব্যবহারের মামলা রয়েছে।

উ: আমি একটি কাতারে দুটি থ্রেড দিয়ে অ্যাক্সেস সিঙ্ক্রোনাইজ করতে চাই।

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

ব্যবহারের ক্ষেত্রে এআই ব্যবহার করে কোডের উদাহরণ দেখুন std::lock_guard<>। ব্যবহারের ক্ষেত্রে বিআই ব্যবহার করে কোড উদাহরণ দেখুন std::unique_lock<>

দুজনের মধ্যে পার্থক্য কী এবং কোনটি ব্যবহারের ক্ষেত্রে আমার একটি ব্যবহার করা উচিত?

উত্তর:


344

পার্থক্যটি হ'ল আপনি লক এবং আনলক করতে পারেন std::unique_lockstd::lock_guardশুধুমাত্র নির্মাণের পরে লক হয়ে যাবে এবং ধ্বংসের সময় তালাবদ্ধ হয়ে যাবে।

সুতরাং বি কেস কেস এর জন্য আপনার অবশ্যই std::unique_lockকন্ডিশন ভেরিয়েবলের প্রয়োজন। এ ক্ষেত্রে এটি নির্ভর করে যে আপনার প্রহরীটিকে পুনরায় স্থানান্তর করতে হবে কিনা।

std::unique_lockএর অন্যান্য বৈশিষ্ট্য রয়েছে যা এটিকে মঞ্জুরি দেয়: যেমন: তাত্ক্ষণিকভাবে মিটেক্সটি লক না করেই তৈরি করা হবে তবে RAII মোড়ক তৈরি করতে ( এখানে দেখুন )।

std::lock_guardএছাড়াও একটি সুবিধাজনক RAII মোড়ক সরবরাহ করে তবে একাধিক মিউটেক্স নিরাপদে লক করতে পারে না। এটি যখন আপনার সীমিত সুযোগের জন্য মোড়কের প্রয়োজন হয় তখন এটি ব্যবহার করা যেতে পারে, যেমন: সদস্য ফাংশন:

class MyClass{
    std::mutex my_mutex;
    void member_foo() {
        std::lock_guard<mutex_type> lock(this->my_mutex);            
        /*
         block of code which needs mutual exclusion (e.g. open the same 
         file in multiple threads).
        */

        //mutex is automatically released when lock goes out of scope           
};

Chmike দ্বারা কোনও প্রশ্ন পরিষ্কার করতে, ডিফল্টরূপে std::lock_guardএবং std::unique_lockএকই রকম। সুতরাং উপরে ক্ষেত্রে, আপনি প্রতিস্থাপন করতে পারে std::lock_guardসঙ্গে std::unique_lock। তবে, std::unique_lockএকটি বাচ্চা আরও ওভারহেড থাকতে পারে।

নোট করুন যে এই দিনগুলির std::scoped_lockপরিবর্তে ব্যবহার করা উচিত std::lock_guard


2
স্ট্যান্ডার্ড :: অনন্য_লক <স্টাড :: মিটেক্স> লক (মাইমুটেক্স) এর নির্দেশ সহ; মিউটেক্স কি কনস্ট্রাক্টর দ্বারা লক হয়ে যাবে?
chmike

3
@ chmike হ্যাঁ, এটি হবে। কিছু স্পষ্টতা যুক্ত।
স্টিফান ডলবার্গ

10
@ chmike ঠিক আছে, আমি মনে করি এটি কার্যকারিতার চেয়ে দক্ষতার প্রশ্ন কম। যদি std::lock_guardআপনার কেস কেসের জন্য যথেষ্ট হয় তবে আপনার এটি ব্যবহার করা উচিত। এটি কেবল অপ্রয়োজনীয় ওভারহেড এড়িয়ে চলে না তবে পাঠকের প্রতি অভিপ্রায়ও দেখায় যে আপনি কখনই এই প্রহরীটিকে আনলক করবেন না।
স্টিফান ডলবার্গ

5
@ চিমিক: তাত্ত্বিকভাবে হ্যাঁ। তবে মিউটিসগুলি হ'ল লাইটওয়েট কনস্ট্রাক্টস নয়, সুতরাং unique_lockসম্ভবত অতিরিক্ত ওভারহেডটি মিউটেক্সকে লকিং এবং আনলক করার ব্যয় দ্বারা বামন হওয়ার সম্ভাবনা রয়েছে (যদি সংকলক যদি ওভারহেডটি অপটিমাইজ করে না, যা সম্ভব হতে পারে)।
গ্রিজলি

6
So for usecase B you definitely need a std::unique_lock for the condition variable- হ্যাঁ তবে কেবল সেই cv.wait()সূত্রেই, কারণ সেই পদ্ধতিটি পরমাণুভাবে মিটেক্সকে প্রকাশ করে। অন্য যে থ্রেডে আপনি ভাগ করা পরিবর্তনশীল (গুলি) আপডেট করেন এবং তারপরে কল করেন সেখানে মুখ্যকে ইন-স্কোপকে তালাবদ্ধ করার জন্য cv.notify_one()একটি সরল lock_guardপ্রত্যয় ... যদি না আপনি আরও কিছু বিশদভাবে করেন যা আমি কল্পনাও করতে পারি না! যেমন en.cppreferences.com/w/cpp/thread/condition_variable - আমার জন্য কাজ করে :)
আন্ডারস্কোর_১

114

lock_guardএবং unique_lockপ্রায় একই জিনিস; lock_guardসীমিত ইন্টারফেস সহ একটি সীমাবদ্ধ সংস্করণ।

একটি lock_guardসর্বদা তার নির্মাণ থেকে ধ্বংস পর্যন্ত একটি লক ধরে থাকে holds একজন unique_lock, অবিলম্বে লক ছাড়া নির্মিত যাবে তার অস্তিত্ব যে কোন সময়ে আনলক করতে পারেন, এবং অন্য এক উদাহরণ হিসেবে বলা যায় থেকে লক মালিকানা হস্তান্তর করতে পারেন।

সুতরাং আপনি সর্বদা ব্যবহার করুন lock_guard, যদি না আপনার সক্ষমতা প্রয়োজন হয় unique_lock। ক condition_variableপ্রয়োজন a unique_lock


11
A condition_variable needs a unique_lock.- হ্যাঁ তবে কেবল wait()আইএনগির পক্ষে, যেমনটি ইনফ করার বিষয়ে আমার মন্তব্যে বিশদভাবে বলা হয়েছে।
আন্ডারস্কোর_১

48

lock_guardযদি unlockনা ক্ষয় না করে আপনি ম্যানুয়ালি মুটেক্সের মধ্যে সক্ষম হবেন না তবে ব্যবহার করুন lock

বিশেষত, condition_variableকল করার সময় ঘুমাতে যাওয়ার সময় এর মিটেক্সটি আনলক করে wait। এ কারণেই lock_guardএখানে একটি যথেষ্ট নয়।


শর্তসাপেক্ষে ভেরিয়েবলের অপেক্ষার পদ্ধতিগুলির মধ্যে একটিতে লক-গার্ড পাস করা ভাল হবে কারণ যে কোনও কারণেই অপেক্ষাটি শেষ হওয়ার পরে মিউটেক্স সর্বদা পুনঃব্যবহৃত হয়। তবে মানকটি কেবল অনন্য_লকের জন্য একটি ইন্টারফেস সরবরাহ করে। এটি স্ট্যান্ডার্ডের ঘাটতি হিসাবে বিবেচিত হতে পারে।
ক্রিস ভাইন

3
@ ক্রিস আপনি এই ক্ষেত্রে এখনও এনক্যাপসুলেশন ভাঙ্গতে চাইবেন। অপেক্ষার পদ্ধতির জন্য মিউটেক্সটিকে মেনটেক্স থেকে বের করে lock_guardআনলক করতে সক্ষম হওয়া দরকার , এইভাবে গার্ডের শ্রেণি আক্রমণকারীটি সাময়িকভাবে ভেঙে যায়। যদিও এটি ব্যবহারকারীর কাছে অদৃশ্য হয়ে যায়, তবুও আমি বিবেচনা করব যে lock_guardএই ক্ষেত্রে ব্যবহারের অনুমতি না দেওয়ার একটি বৈধ কারণ ।
কমিকসানসএমএস

যদি তা হয় তবে এটি অদৃশ্য এবং অন্বেষণযোগ্য হবে। gcc-4.8 এটি করে। অপেক্ষা করুন (অনন্য_লক <মিটেক্স> &) কলগুলি __gthread_cond_wait (& _ M_cond, __ock.mutex () -> নেটিটি_হান্ডেল () দেখুন (libstdc ++ - v3 / src / c ++ 11 / শর্ত_ভরিয়াবল সি সি) দেখুন (লিগবাগ) (দেখুনবাগ /gthr-posix.h)। লক_গার্ডের জন্যও এটি করা যেতে পারে (তবে এটি শর্ত_ভরিবর্তযোগ্যতার জন্য মান হিসাবে নেই)।
ক্রিস ভাইন

4
@ ক্রিস মূল বিষয়টি হ'ল lock_guardঅন্তর্নিহিত মিটেক্সকে পুনরুদ্ধার করার অনুমতি দেয় না। কোড ব্যবহারের lock_guardকোডের বিপরীতে যেসব কোড ব্যবহার করে সেগুলি সম্পর্কে সরল যুক্তির মঞ্জুরি দেওয়ার জন্য এটি একটি ইচ্ছাকৃত সীমাবদ্ধতা unique_lock। আপনি যা চান তা অর্জনের একমাত্র উপায় হ'ল ইচ্ছাকৃতভাবে lock_guardশ্রেণীর এনক্যাপসুলেশন ভেঙে এবং এর বাস্তবায়নটি একটি অন্য শ্রেণীর কাছে প্রকাশ করা (এক্ষেত্রে ক্ষেত্রে condition_variable)। একটি শর্ত ভেরিয়েবলের ব্যবহারকারীকে প্রশ্নবিদ্ধ সুবিধার জন্য দুটি লক ধরণের পার্থক্যের কথা মনে না রাখার জন্য অর্থ প্রদানের পক্ষে এই শক্ত মূল্য।
কমিকসান্সএসএমএস

4
@ ক্রিস আপনি কোথায় এ ধারণাটি পেয়েছেন যা condition_variable_any.waitএকটি নিয়ে কাজ করবে lock_guard? প্রয়োজনীয়তা পূরণের জন্য স্ট্যান্ডার্ডটির সরবরাহকৃত লক ধরণের BasicLockableপ্রয়োজন (meet30.5.2), যা lock_guardহয় না। কেবলমাত্র এর অন্তর্নিহিত মিটেক্সগুলিই করে তবে কারণগুলির জন্য আমি আগে উল্লেখ করেছি যে ইন্টারফেসটি lock_guardমিটেক্সে অ্যাক্সেস সরবরাহ করে না।
কমিকসান্সএসএমএস

11

তার মাঝে কিছু সাধারণ জিনিস lock_guardএবং unique_lockএবং নির্দিষ্ট পার্থক্য।

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

এই ঘটনাটি নীতির বিরুদ্ধে lock_guardlock_guardকেবল একবারই নির্মাণ করা যায় এবং একবারেই ধ্বংস হয়ে যেতে পারে।

সুতরাং lock_guardকন্ডিশন ভেরিয়েবলের সাথে একত্রে ব্যবহার করা যাবে না, তবে unique_lockএটি হতে পারে (কারণ unique_lockবেশ কয়েকবার লক এবং আনলক করা যায়)।


5
he compiler does not allow using a lock_guard in combination with a condition variableএটা মিথ্যা। এটা অবশ্যই নেই অনুমতি এবং সঙ্গে পুরোপুরি কাজ lock_guardউপর notify()ing পাশ। শুধুমাত্র wait()ইনট পাশের জন্য একটি প্রয়োজন unique_lock, কারণ wait()শর্তটি পরীক্ষা করার সময় অবশ্যই লকটি ছেড়ে দিতে হবে।
আন্ডারস্কোর_ড

0

এগুলি সত্যিকারের মতো মিটেক্সস নয়, lock_guard<muType>প্রায় একইরকম std::mutexএকটি পার্থক্যের সাথে এটির পার্থক্য রয়েছে যে তার জীবদ্দশার সুযোগটি স্কোপের শেষে শেষ হয় (ডি-টর নামে পরিচিত) এই দুটি মুটিেক্স সম্পর্কে একটি স্পষ্ট সংজ্ঞা:

lock_guard<muType> একটি স্কোপড ব্লকের সময়কালের জন্য একটি মিটেক্সের মালিকানা দেওয়ার একটি ব্যবস্থা আছে।

এবং

unique_lock<muType> স্থলিত লকিং, লক করার সময়-সীমাবদ্ধ প্রচেষ্টা, পুনরাবৃত্ত লকিং, লকের মালিকানা স্থানান্তরকরণ এবং শর্ত ভেরিয়েবলের সাথে ব্যবহারের অনুমতি দেয় এমন একটি মোড়ক।

এখানে বাস্তবায়ন একটি উদাহরণ:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <chrono>

using namespace std::chrono;

class Product{

   public:

       Product(int data):mdata(data){
       }

       virtual~Product(){
       }

       bool isReady(){
       return flag;
       }

       void showData(){

        std::cout<<mdata<<std::endl;
       }

       void read(){

         std::this_thread::sleep_for(milliseconds(2000));

         std::lock_guard<std::mutex> guard(mmutex);

         flag = true;

         std::cout<<"Data is ready"<<std::endl;

         cvar.notify_one();

       }

       void task(){

       std::unique_lock<std::mutex> lock(mmutex);

       cvar.wait(lock, [&, this]() mutable throw() -> bool{ return this->isReady(); });

       mdata+=1;

       }

   protected:

    std::condition_variable cvar;
    std::mutex mmutex;
    int mdata;
    bool flag = false;

};

int main(){

     int a = 0;
     Product product(a);

     std::thread reading(product.read, &product);
     std::thread setting(product.task, &product);

     reading.join();
     setting.join();


     product.showData();
    return 0;
}

এই উদাহরণে, আমি সাথে ব্যবহার unique_lock<muType>করেছিcondition variable


-5

যেমনটি অন্যদের দ্বারা উল্লেখ করা হয়েছে, স্ট্যান্ড :: অনন্য_লকটি মিউটেক্সের লক অবস্থার উপর নজর রাখে, তাই আপনি লকটি তৈরির পরে লকিং স্থগিত করতে এবং লকটি ধ্বংসের আগে আনলক করতে পারেন। std :: লক_গার্ড এটির অনুমতি দেয় না।

স্ট্যান্ড :: কন্ডিশন_ভেরিয়েবল ওয়েটিং ফাংশনগুলি কোনও লক_গার্ড এবং সেইসাথে একটি অনন্য_লক গ্রহণ না করার কোনও কারণ মনে হচ্ছে না, কারণ যখনই কোনও অপেক্ষা শেষ হয় (যে কোনও কারণেই নাও) মিউটেক্সটি স্বয়ংক্রিয়ভাবে পুনঃপ্রক্রিয়া হয় যাতে কোনও শব্দার্থ লঙ্ঘন না ঘটে। তবে স্ট্যান্ডার্ড অনুসারে, কন্ডিশন ভেরিয়েবল সহ একটি std ::ock_guard ব্যবহার করতে আপনাকে std :: condition_variable_any এর পরিবর্তে std :: condition_variable ব্যবহার করতে হবে।

সম্পাদনা : মুছে ফেলা হয়েছে "pthreads ইন্টারফেস ব্যবহার std :: শর্ত_পরিবর্তনযোগ্য এবং std :: শর্ত_ পরিবর্তনশীল_একটি একই হওয়া উচিত"। সিসির বাস্তবায়নের দিকে তাকিয়ে:

  • স্ট্যান্ড :: কন্ডিশন_ভেরিয়েবল :: ওয়েট (এসটিডি :: অনন্য_লক &) কেবল অনন্য_লক দ্বারা পরিচালিত মিউটেক্সের সাথে অন্তর্নিহিত পাইথ্রেড শর্ত ভেরিয়েবলের উপর pthread_cond_wait () কল করে (এবং তাই লক_গার্ডের জন্য সমানভাবে একই কাজ করতে পারে, তবে মানটি নয় কারণ এর জন্য সরবরাহ করে না)
  • স্ট্যান্ড :: শর্ত_ভরিয়াবল_ যে কোনও লকযোগ্য অবজেক্টের সাথে কাজ করতে পারে, একটি মুটেক্স লক নয় এমনটি সহ (এটি এটি একটি আন্ত-প্রক্রিয়া সেমফোর দিয়েও কাজ করতে পারে)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.