শেয়ারড_মুটেক্স বৃদ্ধির উদাহরণ (একাধিক পঠন / এক লেখার)?


116

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

আমি মনে করি এটি করার জন্য যা boost::shared_mutexকরা উচিত, তবে এটি কীভাবে ব্যবহার করবেন সে সম্পর্কে আমি পরিষ্কার নই, এবং এর একটি সুস্পষ্ট উদাহরণ আমি পাইনি।

আমি কি শুরু করার জন্য ব্যবহার করতে পারি এমন কোনও সাধারণ উদাহরণ রয়েছে?


1800 তথ্যটির উদাহরণটি সঠিক। এই নিবন্ধটি দেখুন: বুস্ট থ্রেডগুলিতে নতুন কী
আসফ লাভি

উত্তর:


102

দেখে মনে হচ্ছে আপনি এরকম কিছু করবেন:

boost::shared_mutex _access;
void reader()
{
  // get shared access
  boost::shared_lock<boost::shared_mutex> lock(_access);

  // now we have shared access
}

void writer()
{
  // get upgradable access
  boost::upgrade_lock<boost::shared_mutex> lock(_access);

  // get exclusive access
  boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
  // now we have exclusive access
}

7
এটি আমার প্রথমবারের মতো বুস্ট ব্যবহার করছে, এবং আমি সি ++ নবাগত, তাই হয়তো আমি এখানে কিছু মিস করছি - তবে আমার নিজের কোডে, আমাকে টাইপটি নির্দিষ্ট করতে হয়েছিল: বুস্ট :: শেয়ারডলক <শেয়ার্ড_মুটেক্স> লক (_access);
কেন স্মিথ

2
আমি নিজে এটি ব্যবহার করার চেষ্টা করছি তবে আমি একটি ত্রুটি পাচ্ছি। 'লক' এর আগে টেম্পলেট আর্গুমেন্ট অনুপস্থিত। কোন ধারনা?
ম্যাট

2
@ Shaz এগুলি স্ক্যাপ করা আছে তবে আপনার প্রয়োজন হলে আপনি তাড়াতাড়ি .unock () দিয়ে মুক্তি দিতে পারেন।
মিমোকনি

4
আমি অনুপস্থিত টেম্পলেট যুক্তি যুক্ত করেছি।

1
@ ইরজ আপনি আপগ্রেড_লকটি পেতে পারেন, তবে ভাগ করা তালটি প্রকাশ না হওয়া অবধি অনন্য লকে আপগ্রেড করা অবরুদ্ধ হয়ে যাবে
1800 তথ্য

166

1800 তথ্য কমবেশি সঠিক, তবে কয়েকটি সমস্যা আছে যা আমি সংশোধন করতে চেয়েছিলাম।

boost::shared_mutex _access;
void reader()
{
  boost::shared_lock< boost::shared_mutex > lock(_access);
  // do work here, without anyone having exclusive access
}

void conditional_writer()
{
  boost::upgrade_lock< boost::shared_mutex > lock(_access);
  // do work here, without anyone having exclusive access

  if (something) {
    boost::upgrade_to_unique_lock< boost::shared_mutex > uniqueLock(lock);
    // do work here, but now you have exclusive access
  }

  // do more work here, without anyone having exclusive access
}

void unconditional_writer()
{
  boost::unique_lock< boost::shared_mutex > lock(_access);
  // do work here, with exclusive access
}

এছাড়াও দ্রষ্টব্য, একটি ভাগ করা তালের বিপরীতে, কেবলমাত্র একটি একক থ্রেড আপগ্রেড না হওয়া সত্ত্বেও এক সময়ে আপগ্রেড_লক অর্জন করতে পারে (যা আমি মনে করি এটির মধ্যে দৌড়ানোর সময় আমি বিশ্রী ছিলাম)। সুতরাং, যদি আপনার সমস্ত পাঠক শর্তসাপেক্ষ লেখক হয় তবে আপনাকে আরও একটি সমাধান খুঁজে বের করতে হবে।


1
শুধু "অন্য একটি সমাধান" মন্তব্য করতে। আমার সমস্ত পাঠক যেখানে শর্তসাপেক্ষ লেখক, আমি যা করেছি তা সর্বদা একটি শেয়ারডলক অর্জন করত এবং যখন প্রাইভেটেজেস লেখার জন্য আমার আপগ্রেড করা দরকার হত তখন আমি পাঠককে লক করে আনতাম () একটি নতুন অনন্য_লক অর্জন করতাম। এটি আপনার আবেদনের যুক্তিকে জটিল করে তুলবে, এবং অন্যান্য লেখকদের জন্য যখন আপনি প্রথম পড়বেন তখন থেকে রাষ্ট্র পরিবর্তন করার সুযোগের উইন্ডো রয়েছে।
মিমোকনি

8
না লাইন উচিত boost::unique_lock< boost::shared_mutex > lock(lock);পড়া boost::unique_lock< boost::shared_mutex > lock( _access ); ?
স্টিভ উইলকিনসন

4
এই শেষ ক্যাব্যাটটি খুব আজব। যদি কেবল একটি থ্রেড একসাথে একটি আপগ্রেড_লক ধরে রাখতে পারে তবে একটি আপগ্রেড_লক এবং একটি অনন্য_লকের মধ্যে পার্থক্য কী?
কেন স্মিথ

2
@ কেন আমি খুব স্পষ্ট ছিল না, তবে আপগ্রেড-লক করার সুবিধাটি হ'ল যদি এখানে কিছু শেয়ারড_লক অর্জিত হয় (কমপক্ষে আপনি অনন্যে আপগ্রেড না হওয়া পর্যন্ত নয়) block তবে, একটি আপগ্রেড_লক চেষ্টা করার এবং অর্জন করার জন্য দ্বিতীয় থ্রেডটি ব্লক হয়ে যাবে, এমনকি যদি প্রথমটি অনন্যতে আপগ্রেড হয় না, যা আমি প্রত্যাশা করি নি।
মিমোকনি

6
এটি একটি পরিচিত উত্সাহ সমস্যা। এটি 1.50 বিটা বৃদ্ধিতে সমাধান হয়েছে বলে মনে হচ্ছে: svn.boost.org/trac/boost/ticket/5516
ওফেক শিলন

47

সি ++ ১ ((ভিএস ২০১৫) যেহেতু আপনি পঠন-লেখার লকগুলির জন্য মান ব্যবহার করতে পারেন:

#include <shared_mutex>

typedef std::shared_mutex Lock;
typedef std::unique_lock< Lock > WriteLock;
typedef std::shared_lock< Lock > ReadLock;

Lock myLock;


void ReadFunction()
{
    ReadLock r_lock(myLock);
    //Do reader stuff
}

void WriteFunction()
{
     WriteLock w_lock(myLock);
     //Do writer stuff
}

পুরানো সংস্করণের জন্য, আপনি একই বাক্য গঠন সহ বুস্ট ব্যবহার করতে পারেন:

#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>

typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock >  WriteLock;
typedef boost::shared_lock< Lock >  ReadLock;

5
আমিও বলব typedef boost::unique_lock< Lock > WriteLock; typedef boost::shared_lock< Lock > ReadLock;
দ্রাক্ষালতা

6
পুরো থ্রেড hpp অন্তর্ভুক্ত করার দরকার নেই। আপনার যদি কেবল লকগুলির প্রয়োজন হয় তবে লকগুলি অন্তর্ভুক্ত করুন। এটি কোনও অভ্যন্তরীণ বাস্তবায়ন নয়। অন্তত অন্তর্ভুক্ত রাখুন।
ইয়োচাই টিমারের

5
অবশ্যই বাস্তবায়ন সহজ তবে আমি মনে করি এটি মুটেক্স এবং লক্স উভয়কেই লক হিসাবে উল্লেখ করা বিভ্রান্তিকর। একটি মিউটেক্স একটি মুটেক্স, একটি লক এমন একটি জিনিস যা এটি একটি লক অবস্থায় রেখে দেয়।
টিম এমবি

17

কেবল আরও কিছু অভিজ্ঞতামূলক তথ্য যুক্ত করতে, আমি আপগ্রেডযোগ্য লক্সের পুরো বিষয়টি এবং বস্ট শেয়ারড_মুটেক্স (একাধিক পঠন / এক লেখার জন্য) উদাহরণটি অনুসন্ধান করেছি? একটি উত্তরের উত্তরটি গুরুত্বপূর্ণ তথ্য যুক্ত করে যে শুধুমাত্র একটি থ্রেডে আপগ্রেড না হওয়া সত্ত্বেও একটি আপগ্রেড লক থাকতে পারে, এটি গুরুত্বপূর্ণ কারণ এর অর্থ আপনি ভাগ করা লকটি প্রথমে ভাগ করা লকটি প্রকাশ না করে অনন্য লকে আপগ্রেড করতে পারবেন না। (এটি অন্য কোথাও আলোচনা করা হয়েছে তবে সবচেয়ে আকর্ষণীয় থ্রেডটি এখানে রয়েছে http://thread.gmane.org/gmane.comp.lib.boost.devel/214394 )

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

  1. যে থ্রেডটি শেয়ারড_মিউটেক্সে একটি অনন্য_লোকের জন্য অপেক্ষা করছে কোনও নতুন পাঠককে ব্লক করে দেয়, তাদের লেখকদের অনুরোধের জন্য অপেক্ষা করতে হবে। এটি নিশ্চিত করে যে পাঠকরা লেখক অনাহারে না পড়ে (তবে আমি বিশ্বাস করি যে লেখকরা অনাহারে থাকতে পারেন)।

  2. যে থ্রেডটি আপগ্রেডযোগ্য_লকের আপগ্রেড হওয়ার অপেক্ষায় রয়েছে তা অন্য থ্রেডগুলিকে একটি ভাগ করা লক পেতে দেয়, তাই পাঠক খুব ঘন ঘন এই থ্রেডটি অনাহারে থাকতে পারে।

এটি বিবেচনা করা একটি গুরুত্বপূর্ণ বিষয়, এবং সম্ভবত নথিভুক্ত করা উচিত।


3
Terekhov algorithmনিশ্চিত যে 1.লেখক পাঠকদের ক্ষুধায় মারা করতে পারবে না। এই দেখুন । তবে 2.সত্য। একটি আপগ্রেড_লোক ন্যায্যতার গ্যারান্টি দেয় না। এই দেখুন ।
জোনাসভৌথেরিন

2

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


(1) আপনি কীভাবে কোনও লেখককে পারমাণবিকভাবে একটি স্বেচ্ছাসেবী পরিমাণ দ্বারা গণনা হ্রাস করতে পারেন ? (২) লেখক যদি কোনওভাবে গণনা শূন্যে হ্রাস করেন তবে ইতিমধ্যে চলমান পাঠকদের লেখার আগে শেষ হওয়ার অপেক্ষায় কীভাবে এটি করা যায়?
ওফেক শিলন

খারাপ ধারণা: দুজন লেখক যদি একই সাথে অ্যাক্সেস করার চেষ্টা করেন তবে আপনার একটি অচলাবস্থা থাকতে পারে।
কাদুচোন

2

জিম মরিসের দুর্দান্ত প্রতিক্রিয়া, আমি এতে হোঁচট খেয়েছি এবং তা বুঝতে আমার কিছুটা সময় লেগেছে। এখানে এমন কিছু সহজ কোড যা দেখায় যে অনন্য_লক বৃদ্ধির জন্য "অনুরোধ" জমা দেওয়ার পরে (সংস্করণ 1.54) সমস্ত ভাগ করা_লক অনুরোধগুলি অবরুদ্ধ করে। এটি অত্যন্ত আকর্ষণীয় বলে মনে হয় যে অনন্য_লক এবং আপগ্রেডযোগ্য_লক এর মধ্যে চয়ন করা যদি আমরা অগ্রাধিকার লিখতে চাই বা অগ্রাধিকার চাই না তবে অনুমতি দেয়।

এছাড়াও (1) জিম মরিসের পোস্টে এটি বিরোধী বলে মনে হচ্ছে: বুস্ট শেয়ার_লক। পড়া পছন্দ?

#include <iostream>
#include <boost/thread.hpp>

using namespace std;

typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock > UniqueLock;
typedef boost::shared_lock< Lock > SharedLock;

Lock tempLock;

void main2() {
    cout << "10" << endl;
    UniqueLock lock2(tempLock); // (2) queue for a unique lock
    cout << "11" << endl;
    boost::this_thread::sleep(boost::posix_time::seconds(1));
    lock2.unlock();
}

void main() {
    cout << "1" << endl;
    SharedLock lock1(tempLock); // (1) aquire a shared lock
    cout << "2" << endl;
    boost::thread tempThread(main2);
    cout << "3" << endl;
    boost::this_thread::sleep(boost::posix_time::seconds(3));
    cout << "4" << endl;
    SharedLock lock3(tempLock); // (3) try getting antoher shared lock, deadlock here
    cout << "5" << endl;
    lock1.unlock();
    lock3.unlock();
}

উপরের কোডটি কেন অচল হয়ে পড়েছে তা জানার জন্য আমার আসলেই সমস্যা হচ্ছে [ স্ট্যাকওভারফ্লো / প্রশ্নগুলি / ২০১২২২৪০৫ /…-তে কোড কাজ করে।
dale1209

1
এটি আসলে (2) এ অচল করে, (3) এ নয়, কারণ (2) (1) এর লকটি প্রকাশের অপেক্ষায় রয়েছে। মনে রাখবেন: একটি অনন্য লক পেতে আপনার বিদ্যমান ভাগ করা সমস্ত লক শেষ হওয়ার অপেক্ষা করতে হবে।
জোনাসভৌথেরিন

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