मैं यह कैसे कर सकता हूं?
class t_scope_lock {
public:
t_scope_lock(MyClass& myClass);
...
private:
boost::scoped_lock d_lock;
};
और MyClass
के लिए इस प्रकार के लिए म्युटेक्स को पहुंच प्रदान करने:
विकल्प 1
एक दृष्टिकोण एक प्रकार है जो एक boost::scoped_lock
है बनाने के लिए किया जाएगा। यदि यह कक्षा विशेष रूप से MyClass
के लिए लिखी गई है, तो मैं इसे एक आंतरिक कक्षा MyClass::t_scoped_lock
के रूप में जोड़ दूंगा।
विकल्प 2
एक और दृष्टिकोण गुंजाइश ताला जो एक (कस्टम) गुंजाइश ताला के निर्माता के लिए परिवर्तनीय हो सकता है के साथ प्रयोग के लिए एक मध्यवर्ती प्रकार बनाने के लिए किया जाएगा। फिर जब वे फिट दिखाई देते हैं तो प्रकार चुन सकते हैं। बहुत से लोगों को कस्टम स्कोप लॉक पसंद नहीं हो सकता है, लेकिन यह आपको अपनी इच्छा के अनुसार, और अच्छी तरह से नियंत्रण के साथ आसानी से निर्दिष्ट करने की अनुमति देगा।
वैकल्पिक 3
कभी कभी यह MyClass
के लिए एक अमूर्त परत जोड़ने के लिए बेहतर है।
{
boost::scoped_lock lock(f->GetScopedLock());
f->LockedFunc1();
f->LockedFunc2();
}
वैकल्पिक 4
कभी कभी तुम एक और लॉक का उपयोग कर सकते हैं (उदाहरण के लिए: अगर वर्ग जटिल है, यह संभावना एक अच्छा समाधान है क्योंकि आप वेरिएंट जो की तरह लग रही का एक बहुत प्रदान करना होगा नहीं हैआंतरिक व बाह्य)।
वैकल्पिक 5
# 4 के समान, आप कुछ मामलों में एक पुनरावर्ती या ReadWrite लॉक का उपयोग कर सकते हैं।
वैकल्पिक 6
आप चुनिंदा प्रकार के इंटरफ़ेस के कुछ भागों को पहुंच प्रदान करने के एक बंद आवरण प्रकार का उपयोग कर सकते हैं।
class MyClassLockedMutator : StackOnly {
public:
MyClassLockedMutator(MyClass& myClass);
// ...
void LockedFunc1() { this->myClass.LockedFunc1(); }
void LockedFunc2() { this->myClass.LockedFunc2(); }
private:
MyClass& myClass;
boost::scoped_lock d_lock; // << locks myClass
};
MyClass f;
MyClassLockedMutator a(f);
a.LockedFunc1();
a.LockedFunc2();
क्या यह समझदार है?
ध्यान रखें कि मुझे नहीं पता कि आपके प्रोग्राम की सटीक बाधाएं क्या हैं (इसलिए, एकाधिक विकल्प)।
विकल्प # 1, # 2, # 3, और # 6 में (वर्चुअल) कोई प्रदर्शन ओवरहेड नहीं है, और कई मामलों में मामूली अतिरिक्त जटिलता है। हालांकि, वे एक ग्राहक के लिए वाक्य रचनात्मक रूप से शोर हैं। आईएमओ, मजबूर शुद्धता जो संकलक जांच सकता है (आवश्यकतानुसार) वाक्य रचनात्मक शोर को कम करने से अधिक महत्वपूर्ण है।
विकल्प # 4 और # 5 अतिरिक्त ओवरहेड/विवाद या लॉकिंग/समवर्ती त्रुटियों और बग पेश करने के अच्छे तरीके हैं। कुछ मामलों में, यह विचार करने के लिए एक साधारण प्रतिस्थापन है।
जब शुद्धता, प्रदर्शन, और/या अन्य प्रतिबंध महत्वपूर्ण हैं, तो मुझे लगता है कि यह उन जटिलताओं को अमूर्त या encapsulate करने के लिए सही अर्थ बनाता है, भले ही यह कुछ वाक्य रचनात्मक शोर या एक अमूर्त परत लागत। मैं ऐसा इसलिए करता हूं क्योंकि ब्रेकिंग में बदलाव करना बहुत आसान है - भले ही मैंने पूरे कार्यक्रम को लिखा और बनाए रखा हो। मेरे लिए, यह दृश्यता का एक और विस्तृत मामला है, और सही ढंग से उपयोग किए जाने पर पूरी तरह समझदार है।
कुछ उदाहरण
नीचे स्क्रॉल main
करने के लिए - इस नमूने नहीं बल्कि बेतरतीब है, क्योंकि यह एक में कई दृष्टिकोण को दर्शाता है:
#include <iostream>
#include <boost/thread.hpp>
class MyClass;
class MyClassOperatorBase {
public:
/* >> public interface */
bool bazzie(bool foo);
protected:
MyClassOperatorBase(MyClass& myClass) : d_myClass(myClass) {
}
virtual ~MyClassOperatorBase() {
}
operator boost::mutex &();
MyClass& getMyClass() {
return this->d_myClass;
}
const MyClass& getMyClass() const {
return this->d_myClass;
}
protected:
/* >> required overrides */
virtual bool imp_bazzie(bool foo) = 0;
private:
MyClass& d_myClass;
private:
/* >> prohibited */
MyClassOperatorBase(const MyClassOperatorBase&);
MyClassOperatorBase& operator=(const MyClassOperatorBase&);
};
class MyClass {
public:
MyClass() : mLock() {
}
virtual ~MyClass() {
}
void LockedFunc1() {
std::cout << "hello ";
}
void LockedFunc2() {
std::cout << "world\n";
}
bool bizzle(bool foo) {
boost::mutex::scoped_lock lock(this->mLock);
return this->imp_bizzle(foo);
}
protected:
virtual bool imp_bizzle(bool foo) {
/* would be pure virtual if we did not need to create it for other tests. */
return foo;
}
private:
class t_scope_lock {
public:
t_scope_lock(MyClass& myClass) : d_lock(myClass.mLock) {
}
private:
boost::mutex::scoped_lock d_lock;
};
protected:
friend class MyClassOperatorBase;
private:
boost::mutex mLock;
};
MyClassOperatorBase::operator boost::mutex &() {
return this->getMyClass().mLock;
}
bool MyClassOperatorBase::bazzie(bool foo) {
MyClass::t_scope_lock lock(this->getMyClass());
return this->imp_bazzie(foo);
}
class TheirClassOperator : public MyClassOperatorBase {
public:
TheirClassOperator(MyClass& myClass) : MyClassOperatorBase(myClass) {
}
virtual ~TheirClassOperator() {
}
bool baz(bool foo) {
boost::mutex::scoped_lock lock(*this);
return this->work(foo);
}
boost::mutex& evilClientMove() {
return *this;
}
protected:
virtual bool imp_bazzie(bool foo) {
return this->work(foo);
}
private:
bool work(bool foo) {
MyClass& m(this->getMyClass());
m.LockedFunc1();
m.LockedFunc2();
return foo;
}
};
class TheirClass : public MyClass {
public:
TheirClass() : MyClass() {
}
virtual ~TheirClass() {
}
protected:
virtual bool imp_bizzle(bool foo) {
std::cout << "hallo, welt!\n";
return foo;
}
};
namespace {
/* attempt to restrict the lock's visibility to MyClassOperatorBase types. no virtual required: */
void ExampleA() {
MyClass my;
TheirClassOperator their(my);
their.baz(true);
// boost::mutex::scoped_lock lock(my); << error inaccessible
// boost::mutex::scoped_lock lock(my.mLock); << error inaccessible
// boost::mutex::scoped_lock lock(their); << error inaccessible
boost::mutex::scoped_lock lock(their.evilClientMove());
}
/* restrict the lock's visibility to MyClassOperatorBase and call through a virtual: */
void ExampleB() {
MyClass my;
TheirClassOperator their(my);
their.bazzie(true);
}
/* if they derive from my class, then life is simple: */
void ExampleC() {
TheirClass their;
their.bizzle(true);
}
}
int main(int argc, const char* argv[]) {
ExampleA();
ExampleB();
ExampleC();
return 0;
}
मैं इस पर एक अलग मुद्दे की तलाश में ठोकर खाई। लेकिन, मुझे क्या लगता है कि MyClass के लॉक * आउट * को पार करना वास्तव में आप जो करना चाहते हैं उसके विपरीत है। इसके बजाय, आप वास्तव में जो चाहते हैं वह है MyClass पर एक विधि जिसे "ExecuteAtomically" या "ExecuteLocked" कहा जाता है, जिसे आप किसी प्रकार की लैम्ब्डा अभिव्यक्ति को पारित कर सकते हैं जिसमें लॉक होने के संदर्भ में आप जो भी कोड चाहते हैं उसका मूल्यांकन किया जाता है। मैं बूस्ट/सी ++ के साथ ऐसा करने का सबसे अच्छा तरीका जानने की कोशिश कर रहा हूं, लेकिन हो सकता है कि मेरे से कोई भी चालाक हो सकता है। –
@ChrisCleeland: यह समस्या के बारे में सोचने का एक बहुत ही दिलचस्प तरीका है। –
इसके बारे में थोड़ा और सोचा, और मुझे लगता है कि यह किया जा सकता है। "निष्पादन" विधि में निष्पादन जैसे कुछ निष्पादन हो सकता है (boost :: function) ताकि आप एक मज़ेदार को परिभाषित कर सकें और पहले तर्क के लिए "यह" (या * यह) बांध सकें। यह अनुमान लगाता है कि ठीक से काम करता है (जो मुझे लगता है), यह फॉस्टर के शरीर को स्थानांतरित करने के लिए बूस्ट :: लैम्ब्डा (या नई भाषा सुविधा) को नियोजित करने के लिए बहुत अधिक काम नहीं होना चाहिए ताकि यह कॉल के साथ जगह हो निष्पादन हेतु()। मुझे आशा थी कि मैं इसे आजमाने के लिए अपनी वर्तमान कार्य सूची में एक जगह का पता लगा सकता हूं, लेकिन मैंने नहीं किया है। बाद में कोशिश कर सकते हैं। –